pure icon indicating copy to clipboard operation
pure copied to clipboard

Pure does not respect $GIT_DIR and $GIT_WORK_TREE

Open zhimsel opened this issue 4 years ago • 3 comments

General information

With pure prompt, git status is not displayed if you use a different git dir path (and set $GIT_DIR and $GIT_WORK_TREE accordingly).

System report (output of prompt_pure_system_report):

- Zsh: zsh 5.8 (x86_64-pc-linux-gnu) (/usr/bin/zsh)
- Operating system: Linux (#1 ZEN SMP PREEMPT Wed, 06 May 2020 17:32:39 +0000)
- Terminal program: Konsole 20.04.0 (but also occurs in latest iTerm2)
- Tmux: yes
- Git: git version 2.26.2
- Pure state:
    - username: `''`
    - prompt: `❯`
    - version: `1.11.0`
- PROMPT: `typeset -g PROMPT=$'%F{${prompt_pure_colors[path]}}%~%f
%{
%}%(12V.%F{$prompt_pure_colors[virtualenv]}%12v%f .)%(?.%F{$prompt_pure_colors[prompt:success]}.%F{$prompt_pure_colors[prompt:error]})${prompt_pure_state[prompt]}%f '`
- Colors: `typeset -g -A prompt_pure_colors=( [execution_time]=yellow [git:action]=yellow [git:arrow]=cyan [git:branch]=magenta [git:branch:cached]=red [git:dirty]=218 [git:stash]=cyan [host]=yellow [path]=blue [prompt:continuation]=242 [prompt:error]=red [prompt:success]=green [user]=green [user:root]=default [virtualenv]=242 )`
- Virtualenv: `export VIRTUAL_ENV_DISABLE_PROMPT=1`
- Conda: `export CONDA_CHANGEPS1=no`
- Detected frameworks: None

I have:

  • [x] Tested with another terminal program and can reproduce the issue:
  • [x] Followed the integration instructions for my framework

Problem description

$GIT_DIR and $GIT_WORK_TREE are not respected unless already set before prompt is loaded.

Reproduction steps

  1. Open shell with pure prompt (see .zshrc below)
  2. Create empty git repo with non-traditional git_dir:
cd /tmp/puregit
export GIT_DIR=`pwd`/.notgit GIT_WORK_TREE=`pwd`
git init
  1. Confirm that git is working as expected (and picks up the git repo in the ./.notgit dir:
git status
  1. Observe that the prompt does not display the git branch
  2. Launch a new zsh (from this shell)
zsh
  1. Observe that the prompt now displays the git branch

My .zshrc:

#!/usr/bin/env zsh

declare -A ZINIT
ZINIT[HOME_DIR]="$HOME/.zinit"
ZINIT[BIN_DIR]="${ZINIT[HOME_DIR]}/bin"

source "${ZINIT[BIN_DIR]}/zinit.zsh"

zinit ice compile'(pure|async).zsh' pick'async.zsh' src'pure.zsh'
zinit light "sindresorhus/pure"

Thoughts

I think this is related to the fact that the vcs_info stuff is done in an async subshell(?). When you export the git env vars, they aren't passed to the async processes, so they don't take them into account.

Is there any way to have the async process get these variables after it's initialized? It doesn't have to be immediate (since, you know, it's async), but the next vcs_info check should be passed these variables.

zhimsel avatar May 15 '20 03:05 zhimsel

It's possible to update the env info in the async worker via the async_worker_eval, here's an example use already in Pure: https://github.com/sindresorhus/pure/blob/02643fd167b6bace2f31ad248fc317e32a42d3fd/pure.zsh#L399

There we change the directory, but it could just as well be an export GIT_DIR=... to set or a unset GIT_DIR to remove.

A good place to detect this could be in prompt_pure_preexec as that is after the user has issued a command or then it could always be done as part of prompt_pure_async_tasks. Since we're anyway issuing one worker eval there, it might be most performant to combine them. Perhaps something like:

async_worker_eval "prompt_pure" "builtin cd -q ${(q)PWD}; export GIT_DIR=${(q)GIT_DIR}" ...

The reason we're using (q) for variables here is that it performs necessary shell escaping on the input so that the command(s) will be interpreted correctly. It's a small current limitation of the eval implementation in zsh-async where if we want to issue multiple commands (i.e. use ;) we must quote the entire input.

mafredri avatar Sep 19 '20 12:09 mafredri

Is that something that should be done user-side? Or within pure itself?

zhimsel avatar Sep 23 '20 14:09 zhimsel

Hmm, it could be either TBH. I guess the question is, do people rely on this functionality and expect Pure to obey the variables? Which is more intuitive?

This should work:

async_git_envs() {
      async_worker_eval "prompt_pure" 'git_dir='"${(q)GIT_DIR}"'; git_work_tree='"${(q)GIT_WORK_TREE}"'; if [[ -n $git_dir ]]; then export GIT_DIR=$git_dir; else unset GIT_DIR; fi; if [[ -n $git_work_tree ]]; then export GIT_WORK_TREE=$git_work_tree; else unset GIT_WORK_TREE; fi'
}
add-zsh-hook preexec async_git_envs

mafredri avatar Sep 23 '20 14:09 mafredri