Giter VIP home page Giter VIP logo

zsh-autoenv's Introduction

Build Status

Autoenv for Zsh

zsh-autoenv automatically sources (known/whitelisted) .autoenv.zsh files, typically used in project root directories.

It handles "enter" and leave" events, nesting, and stashing of variables (overwriting and restoring).

Requirements

  • Zsh version 4.3.10 or later.

Features

  • Support for enter and leave events, which can use the same file. By default it uses .autoenv.zsh for entering, and .autoenv_leave.zsh for leaving.
  • Interactively asks for confirmation / authentication before sourcing an unknown .autoenv.zsh file, and remembers whitelisted files by their hashed content.
  • Test suite.
  • Written in/for Zsh.

Variable stashing

You can use autostash in your .autoenv.zsh files to overwrite some variable, e.g. $PATH. When leaving the directory, it will be automatically restored.

% echo 'echo ENTERED; autostash FOO=changed' > project/.autoenv.zsh
% FOO=orig
% cd project
Attempting to load unauthorized env file!
-rw-rw-r-- 1 user user 36 Mai  6 20:38 /tmp/project/.autoenv.zsh

**********************************************

echo ENTERED; autostash FOO=changed

**********************************************

Would you like to authorize it? (type 'yes') yes
ENTERED
project % echo $FOO
changed
% cd ..
% echo $FOO
orig

There is also stash, unstash and autounstash, in case you want to have more control.

The varstash library has been taken from smartcd, and was optimized for Zsh.

Writing your .autoenv.zsh file

autoenv_source_parent()

zsh-autoenv will stop looking for .autoenv.zsh files upwards after the first one has been found, but you can use the function autoenv_source_parent to source the next .autoenv.zsh file upwards the directory tree from there.

The function accepts an optional argument, which allows to stop looking before the file system root is reached:

autoenv_source_parent ../..

Installation

Clone the repository and source it from your ~/.zshrc file:

% git clone https://github.com/Tarrasch/zsh-autoenv ~/.dotfiles/lib/zsh-autoenv
% echo 'source ~/.dotfiles/lib/zsh-autoenv/autoenv.zsh' >> ~/.zshrc

Using antigen

antigen-bundle Tarrasch/zsh-autoenv

Using zgen

Add the following to your .zshrc where you are loading your plugins:

zgen load Tarrasch/zsh-autoenv

Using zplug

Add the following to your .zshrc where you are loading your plugins:

zplug "Tarrasch/zsh-autoenv"

Configuration

You can use the following variables to control zsh-autoenv's behavior. Add them to your ~/.zshrc file, before sourcing/loading zsh-autoenv.

AUTOENV_FILE_ENTER

Name of the file to look for when entering directories.

Default: .autoenv.zsh

AUTOENV_FILE_LEAVE

Name of the file to look for when leaving directories. Requires AUTOENV_HANDLE_LEAVE=1.

Default: .autoenv_leave.zsh

AUTOENV_LOOK_UPWARDS

Look for zsh-autoenv "enter" files in parent dirs?

Default: 1

AUTOENV_HANDLE_LEAVE

Handle leave events when changing away from a subtree, where an "enter" event was handled?

Default: 1

AUTOENV_DISABLED

(Temporarily) disable zsh-autoenv. This gets looked at in the chpwd handler.

Default: 0

AUTOENV_DEBUG

Set debug level. If enabled (> 0) it will print information to stderr.

  • 0: no debug messages
  • 1: generic debug logging
  • 2: more verbose messages
    • messages about adding/removing files on the internal stack
  • 3: everything
    • sets xtrace option (set -x) while sourcing env files

Default: 0

Usage

zsh-autoenv works automatically once installed.

You can use autoenv-edit to edit the nearest/current autoenv files. It will use $AUTOENV_EDITOR, $EDITOR, or vim for editing.

Helper functions

The following helper functions are available:

autoenv_append_path

Appends path(s) to $path ($PATH), if they are not in there already.

autoenv_prepend_path

Prepends path(s) to $path ($PATH), if they are not in there already.

autoenv_remove_path

Removes path(s) from $path ($PATH).

Returns 0 in case $path has changed, 1 otherwise.

Recipes

Automatically activate Python virtualenvs

Given AUTOENV_FILE_ENTER=.autoenv.zsh, AUTOENV_FILE_LEAVE=.autoenv.zsh and AUTOENV_HANDLE_LEAVE=1 the following script will activate Python virtualenvs automatically in all subdirectories (.venv directories get used by pipenv with PIPENV_VENV_IN_PROJECT=1):

# Environment file for all projects.
#  - (de)activates Python virtualenvs (.venv) from pipenv

if [[ $autoenv_event == 'enter' ]]; then
  autoenv_source_parent

  _my_autoenv_venv_chpwd() {
    if [[ -z "$_ZSH_ACTIVATED_VIRTUALENV" && -n "$VIRTUAL_ENV" ]]; then
      return
    fi

    setopt localoptions extendedglob
    local -a venv
    venv=(./(../)#.venv(NY1:A))

    if [[ -n "$_ZSH_ACTIVATED_VIRTUALENV" && -n "$VIRTUAL_ENV" ]]; then
      if ! (( $#venv )) || [[ "$_ZSH_ACTIVATED_VIRTUALENV" != "$venv[1]" ]]; then
        unset _ZSH_ACTIVATED_VIRTUALENV
        echo "De-activating virtualenv: ${(D)VIRTUAL_ENV}" >&2

        # Simulate "deactivate", but handle $PATH better (remove VIRTUAL_ENV).
        if ! autoenv_remove_path $VIRTUAL_ENV/bin; then
          echo "warning: ${VIRTUAL_ENV}/bin not found in \$PATH" >&2
        fi

        # NOTE: does not handle PYTHONHOME/_OLD_VIRTUAL_PYTHONHOME
        unset _OLD_VIRTUAL_PYTHONHOME
        # NOTE: does not handle PS1/_OLD_VIRTUAL_PS1
        unset _OLD_VIRTUAL_PS1
        unset VIRTUAL_ENV
      fi
    fi

    if [[ -z "$VIRTUAL_ENV" ]]; then
      if (( $#venv )); then
        echo "Activating virtualenv: ${(D)venv}" >&2
        export VIRTUAL_ENV=$venv[1]
        autoenv_prepend_path $VIRTUAL_ENV/bin
        _ZSH_ACTIVATED_VIRTUALENV="$venv[1]"
      fi
    fi
  }
  autoload -U add-zsh-hook
  add-zsh-hook chpwd _my_autoenv_venv_chpwd
  _my_autoenv_venv_chpwd
else
  add-zsh-hook -d chpwd _my_autoenv_venv_chpwd
fi

Related projects

History

This started as an optimized version of the bash plugin autoenv but for Zsh, and grew a lot of functionality on top of it (inspired by smartcd).

The code was initially based on @joshuaclayton's dotfiles. In September 2013 @Tarrasch packaged it into a nice antigen-compatible unit with integration tests. Since November 2014, @blueyed took over and added many nice features, mainly inspired by smartcd.

zsh-autoenv's People

Contributors

blueyed avatar mickaelperrin avatar qur2 avatar rspeed avatar srijanshetty avatar tarrasch avatar unixorn avatar wikibootup avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zsh-autoenv's Issues

Stash/unstash of $PATH doesn't remove path correctly

I have the following bug.

I try to stash two paths to $PATH. I will call them below like this:

  • code/bin is my custom path (in the log below it is /home/kabanod/job/ffm/shock-attached/code/bin)
  • python/bin is path to python interpreter (in the log below it is /home/kabanod/apps/python/3.4/bin)

What do I do? In .autoenv.zsh I prepend $PATH with the path to the python/bin directory using Environment Modules command (module load python/3.4) and then prepend $PATH with code/bin path (using stash command). In .autoenv_leave.zsh I unstash $PATH from my code/bin path and then unload python/bin path.

Expected behavior. Both paths are removed from $PATH.

What happens. python/bin path is removed from $PATH, however, an explicit call to stash doesn't remove code/bin path from $PATH.

I also tried to use autostash functionality with no success.

This is the full log:

kabanod@kw12608 ~/job/ffm/shock-attached
  % echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

kabanod@kw12608 ~/job/ffm/shock-attached
  % cd good-experiments 
Attempting to load unauthorized env file!
-rw-r--r-- 1 kabanod kw-users 260 May 22 18:21 /home/kabanod/job/ffm/shock-attached/good-experiments/.autoenv.zsh

**********************************************

echo "Begin '.autoenv.zsh': " $PATH
module load python/3.4
echo "After 'module load python/3.4': " $PATH

code_path=$HOME/job/ffm/shock-attached/code

autostash PYTHONPATH=$code_path:
stash PATH=$code_path/bin:$PATH
echo "After stash: " $PATH

unset code_path

**********************************************

Would you like to authorize it? (type 'yes') yes
Begin '.autoenv.zsh':  /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
After 'module load python/3.4':  /home/kabanod/apps/python/3.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
After stash:  /home/kabanod/job/ffm/shock-attached/code/bin:/home/kabanod/apps/python/3.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

kabanod@kw12608 ~/job/ffm/shock-attached/good-experiments
± % cd ..
Attempting to load unauthorized env file!
-rw-r--r-- 1 kabanod kw-users 157 May 22 18:21 /home/kabanod/job/ffm/shock-attached/good-experiments/.autoenv_leave.zsh

**********************************************

echo "Begin '.autoenv_leave.zsh': " $PATH
unstash PATH
echo "After unstash: " $PATH
module unload python/3.4
echo "After 'module unload python/3.4': " $PATH

**********************************************

Would you like to authorize it? (type 'yes') yes
Begin '.autoenv_leave.zsh':  /home/kabanod/job/ffm/shock-attached/code/bin:/home/kabanod/apps/python/3.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
After unstash:  /home/kabanod/job/ffm/shock-attached/code/bin:/home/kabanod/apps/python/3.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
After 'module unload python/3.4':  /home/kabanod/job/ffm/shock-attached/code/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

kabanod@kw12608 ~/job/ffm/shock-attached
  % echo $PATH
/home/kabanod/job/ffm/shock-attached/code/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

variables not properly exported ?

hi,

in my .autoenv.zsh i set

KAFKA_BROKERS="192.168.99.100:9092"

when i enter the directory i can do
echo $KAFKA_BROKERS which works as expected
however when i run export -a the variables is not listed there hence it does not work in my Elixir project

I use

zsh --version
zsh --version
zsh 5.0.8 (x86_64-apple-darwin15.0)

with latest zgen

Does not work with shwordsplit option (endless loop with path containing space)

Check this out:

% mkdir "foo bar baz"
cd foo\ bar\ baz
[ prompt doesn't return... ]

Top reports:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                     
 5096 zcalusic  20   0   57284  15988   1600 R 100.0  0.1   0:06.18 zsh                         

Zsh is stuck in some kind of loop. Ctrl-C helps to get out of it. It happens only if 2 or more spaces are in directory name.

This started happening after I installed zsh-autoenv.

Other than this bug, it's really cool, solves some things very nicely!

Add helper function to handle .env files

After seeing the docs I am not fully clear so I am asking this question.

I have a .env or *.env files e.g production.env or local.env in a repository where my different configs & credentials stored. I am looking for whenever I cd into that directory I want to load my all *.env files or at least .env file & when I move to parent directory it will restore the previous values of env variable that was modified e.g PATH variable & will remove the other ones that were added.

I am using oh-my-zsh I have tried autoenv but that didn't work also I saw a comment from this repos contributor @blueyed hyperupcall/autoenv#30 (comment) where he says this unload feature is available in this project.

Also in oh-my-zsh when we type a directory & press enter & it just cd into that directory, no need to type cd in oh-my-zsh. So is it already implemented to load .env files without use cd just typing the directory name & going into the directory.

Thanks

Way to invoke _autoenv_chpwd_handler from script ?

Hi,

I use a script that generate .autoenv.zsh files.

Is it possible to call _autoenv_chpwd_handler from this script and get it working in the current terminal session when it ends ?

I would like to prevent the need to call _autoenv_chpwd_handler manually or to leave/enter the current directory when the script ends.

Don't see how it could be possible, but you can have some hints.

Regards,

Use the same file for enter and leave? (AUTOENV_FILE_LEAVE)

Currently $AUTOENV_FILE_LEAVE defaults to .env.leave, which .env is being used for "enter".

I am using AUTOENV_FILE_LEAVE=.env myself from the beginning.

I find it more convenient to have it in a single file and use $autoenv_event to check which event is being used.

What's your opinion on this?

(I've mentioned this previously already, and IIRC .env.leave was used to not break backwards compatibility).

Change format of "not authenticated" message?

I think it might be better to use the output from ls -l with the confirmation message:

Attempting to load unauthorized env file:
-rw-rw-r-- 1 user user 134 Nov 23 14:10 path/to/.env

What do you think?

This should get changed on top of the next branch then.

Using zsh `..` instead of `cd ..` does not trigger `.autoenv-leave.zsh`

When exiting a directory containing .autoenv-leave.zsh I often use .. instead of cd .. and this does not trigger .autoenv-leave.zsh on first use. Would be a handy improvement!

Thanks for this great work.

Here are my relevant files:

───────┬────────────────────────────────────────────────────────────────────────
       │ File: .autoenv.zsh
───────┼────────────────────────────────────────────────────────────────────────
   1   │ echo ACTIVATING openai; conda activate openai
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
       │ File: .autoenv_leave.zsh
───────┼────────────────────────────────────────────────────────────────────────
   1   │ echo DEACTIVATING openai; conda deactivate
───────┴────────────────────────────────────────────────────────────────────────

Fix issues with running tests on macOS

More of a reminder to myself.

In short: The tests assume that mktemp generates everything under /tmp, but that isn't the case on macOS. So… gotta fix that.

Error when entering any directory

This is happening with the latest master branch installed as an anitgen bundle

_autoenv_debug:local:1: not valid in this context: handler:

Error if path contains spaces

I am using zsh-autoenv on OS X and it breaks if the path where the .autoenv.zsh file is saved contains spaces. The error message is the following:

cd ~/test\ folder
_autoenv_authorized_env_file:local:2: not valid in this context: folder/.autoenv.zsh:423624aee303faed668094684c5156df46d491a2:1

I tried adding quotes around $1 in the _autoenv_autorized_env_file definition in autoenv.zsh, but it does not make any difference. I also tried using ${(q)env_file} instead of $env_file when calling _autoenv_hash_pair, but then it complains about a missing file argument for the function.

Load env file from parent directories

.env files from parent directories could be looked for / handled, too.

E.g. cd'ing to /foo/bar/baz would also look for .env in /foo/bar, /foo and /, using the first one it finds.

autostash not working when changing out of child directory

autostash appears to not restore/unset environment variables when changing out of a child directory instead of the directory where autostash is part of the .autoenv.zsh file.

Steps to reproduce:

  1. export AUTOENV_LOOK_UPWARDS=1
  2. Create a directory ~/env1
  3. Create ~/env1/.autoenv.zsh with "autostash TEST=YES"
  4. Create a directory ~/env1/env2
  5. Open a new shell starting at ~
  6. cd into ~/env1/env2 -> echo $TEST is now YES
  7. cd into ~ directly

Current behavior

-> echo $TEST is still YES

Expected behavior

-> echo $TEST is empty

Environment variables override on new terminal

I'm having troubles when opening a new terminal tab in a directory with .autoenv.sh.

Here's how my .autoenv.sh looks like:

source `dirname "$0:A"`/.venv/bin/activate #activates virtualenv
echo `which python` # for testing purpose

So let's say I have my first terminal and cd into the directory:

$ cd Devel/Python/my_project
/Users/redrabbit/Devel/Python/my_project/.venv/bin/python <--- echoed from .autoenv.sh
$ which python
/Users/redrabbit/Devel/Python/my_project/.venv/bin/python <--- OK

Everything OK here. I'm using python from my $VIRTUAL_ENV.

Now i open a new tab within the Terminal app (cmd+t):

Last login: Sat Jun 11 14:26:34 on ttys000
/Users/redrabbit/Devel/Python/my_project/.venv/bin/python <--- echoed from .autoenv.sh
$ which python
/usr/local/bin/python <--- ??? Something went wrong here

It looks like $PATH is reseted to its old value right after .autoenv.sh is executed.

error message, not working

after install:

Would you like to authorize it? (type 'yes') yes
_autoenv_authorize:3: no such file or directory: /root/.local/share/autoenv_auth

programmatically pre-authorize files

I'm used to copy my "default" autoenv script whenever I go with a scrtipt which set up venv. how would it be possible to pre-authorize script if I copied it myself from known location?

Use AUTOENV_ prefix for variables

What's the name of the project?

While going wild on the source, I've used the "dotenv" name for vars etc, because it was used internally already.

Should this get refactored to use AUTOENV_* vars?
This would be nice to have it as a drop-in replacement for https://github.com/kennethreitz/autoenv - as long as it uses the same mechanism for AUTOENV_ENV_FILENAME etc.

Support for stashing of variables, functions etc

I am considering to include varstash from https://github.com/cxreg/smartcd/, which could then be used like this:

# Source/activate it explicitly, or have the functions defined already?!
source …/zsh-autoenv/lib/varstash

if [[ $_dotenv_event == 'enter' ]]; then
  pyenv activate foo

  autostash PATH=$_dotenv_cwd/bin:$PATH
  autostash DJANGO_SETTINGS_MODULE=config.settings
  autostash ENVDIR=$_dotenv_cwd/envdir
  autostash PYTHONPATH=$_dotenv_cwd/tmm

else
  if [ "$VIRTUAL_ENV" = "foo" ]; then
    pyenv deactivate
  fi

  # Restore vars that had been stashed before.
  autounstash
fi

How to set path at locality of .autoenv.zsh?

Hello,

I have /home/user/src/ansible/myProject/.autoenv.zsh that looks like this:

echo Setting environment variables...
autostash ANSIBLE_CONFIG=${PWD}/ansible.cfg

I want ${PWD} to be the path where the .autoenv.zsh is at in the tree.

If I cd deeper into the tree such as /home/user/src/ansible/myProject/roles/myrole/tasks
I still want ANSIBLE_CONFIG to be /home/user/src/ansible/myProject/ansible.cfg not:
/home/user/src/ansible/myProject/roles/myrole/tasks/ansible.cfg

Thanks!

Path to the .autoenv.zsh file when loaded from a parent directory

Hello.

One of my use cases for zsh-autoenv is to automatically activate Python virtual environments within projects, and my issue with this particular use case is this:

Upon cd-ing to a project subdirectory, zsh-autoenv's default behaviour is to bubble up parent directories looking for a .autoenv.zsh script (which is desired). If one's found, it gets executed with $PWD set to the dir I cd'd into, not the dir where it was found. While this is a reasonable default, scripts relying on path relative to the project root (determined by the path to the .autoenv.zsh file) get broken.

My proposal is to (temporarily) export something like $AUTOENV_FILE_ENTER_PATH when looking for an env script in parent directories. This would allow us to write autoenv scripts relative to the project root without changing zsh-autoenv's default behaviour or impacting existing scripts.

Let me know what you think, or whether I'm missing something here.

Thanks in advance

How to ensure .zshrc is already sourced before running autoenv commands?

Related to #2 -- here's some trouble I have with the ordering of events:

  • I have autoenv files which run functions defined in my ~/.zshrc
  • I am in a folder with such an autoenv configuration
  • I open a new tmux pane in the current path:
    % tmux bind l new-window -c "#{pane_current_path}"
  • Autoenv tries to run those functions, but they are not yet defined

It looks like it's the last line of the plugin, calling _autoenv_chpwd_handler at the time the plugin is sourced.

So I guess that means I can work around this by loading this plugin after I define the things it'll need.

I wonder though if it might make sense to temporarily add the function to a different hook, then remove it. Yup, that seems to work. I'll submit a PR.

Allow to store "no" in authentication permanently

Saying "no" (not "yes") to the "Would you like to authorize it?" question should not ask you again in the same shell session.

Additionally, a "no, never" option would allow to store this information (with the current hash) in the authorization file.

When ignoring a file because of this, a note might be displayed - once per shell session.

This would look like this then:

Would you like to authorize it? (type 'yes', or 'no' to not being asked about the file again)

I feel like the explanation should be better, maybe across two lines. It should also mention that everything else ignores it for the current shell.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.