├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── ci.yml
├── .gitignore
├── .markdownlint.json
├── .npmrc
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── activate.sh
├── aur
├── autoenv-git
│ └── PKGBUILD
└── autoenv
│ └── PKGBUILD
├── autoenv.plugin.zsh
├── docs
├── uninstall.md
└── updating.md
├── package.json
├── scripts
└── install.sh
├── shelltestrunner.sh
├── shelltests
├── api.sh
├── cd.sh
└── env.sh
└── tests
├── functions
├── test.sh
├── test_auth_spaces.sh
├── test_cd_env.sh
├── test_cd_env_leave.sh
├── test_cd_spaces.sh
├── test_colons.sh
├── test_custom_filename.sh
├── test_default.bats
├── test_doubleslash.sh
├── test_noclobber.sh
├── test_not_file.sh
├── test_paths.bats
├── test_prompt.bats
├── test_simple.sh
├── test_symlink.sh
├── test_variables.bats
└── util
├── init.sh
└── test_util.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.{md,yaml,yml}]
11 | indent_style = space
12 | indent_size = 2
13 | quote_type = single
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: type/bug
6 | assignees: ''
7 | ---
8 |
9 | **Platform**
10 | - Operating system and version?
11 | - Shell and version?
12 | - autoenv installation method
13 | - autoenv version
14 |
15 | **Describe the bug**
16 |
17 | A clear and concise description of what the bug is.
18 |
19 | **Expected behavior**
20 |
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Additional context**
24 |
25 | Add any other context about the problem here.
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: type/feature
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 |
12 | A clear and concise description of what the problem is
13 |
14 | **Describe the solution you'd like**
15 |
16 | A clear and concise description of what you want to happen.
17 |
18 | **Describe alternatives you've considered**
19 |
20 | A clear and concise description of any alternative solutions or features you've considered.
21 |
22 | **Additional context**
23 |
24 | Add any other context or screenshots about the feature request here.
25 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: 'ci'
2 |
3 | on: ['push', 'pull_request']
4 |
5 | permissions: 'read-all'
6 |
7 | defaults:
8 | run:
9 | shell: 'bash'
10 | working-directory: './'
11 |
12 | jobs:
13 | test-mac:
14 | name: 'MacOS Test'
15 | strategy:
16 | fail-fast: false
17 | matrix:
18 | os: ['macos-latest']
19 |
20 | runs-on: '${{ matrix.os }}'
21 |
22 | steps:
23 | - uses: 'actions/checkout@v2'
24 |
25 | - name: 'Install Prerequisites'
26 | run: |
27 | brew install coreutils bash zsh dash fish ksh tcsh bats-core
28 |
29 | - name: 'Run tests'
30 | run: |
31 | time make test
32 | # time make test-bats
33 | # time make test2
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | tests/lasttest.log
3 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "commands-show-output": false,
3 | "line-length": false,
4 | "no-inline-html": false,
5 | "no-duplicate-heading": false
6 | }
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock = false
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | The format of this file is based on [Keep a Changelog](http://keepachangelog.com); this project adheres to [Semantic Versioning](http://semver.org).
4 |
5 | ## [v0.4.0] - 2025-04-08
6 |
7 | Another yet-again long-awaited release! 🥳
8 |
9 | As per the title, this mostly includes features, but also includes the usual bug fixes, documentation updates, and maintenance chores.
10 |
11 | ### Features
12 |
13 | ##### Add ability to disable sourcing of particular `.env` files
14 |
15 | When `cd`ing to a directory with an `.env` (by default) file, `autoenv` used to _always prompt_ to source the file:
16 |
17 | ```console
18 | $ cd ./dir
19 | autoenv: WARNING:
20 | autoenv: This is the first time you are about to source /home/edwin/autoenv/.hidden/.env:
21 | autoenv:
22 | autoenv: --- (begin contents) ---------------------------------------
23 | autoenv: echo '.env has been sourced.'$
24 | autoenv:
25 | autoenv: --- (end contents) -----------------------------------------
26 | autoenv: Are you sure you want to allow this? (y/N)
27 | ```
28 |
29 | Even when selecting `n` (no), autoenv would not remember that choice. Now, there is a new option!:
30 |
31 | ```console
32 | $ AUTOENV_VIEWER=cat cd ./dir
33 | [autoenv] New or modified env file detected:
34 | --- Contents of ".env" --------------------------------------------------------------------------------
35 | echo '.env has been sourced.'
36 | -------------------------------------------------------------------------------------------------------
37 | [autoenv] Authorize this file? (y/n/d)
38 | ```
39 |
40 | Choose `d` (disable) if you no longer want any "source prompts" for this file. Note that if the file content changes, then your choice is reset and `autoenv` will prompt you yet again.
41 |
42 | The `AUTOENV_NOTAUTH_FILE` shell variable is used to configure where this data is stored. Its format is identical to the one in `AUTOENV_AUTH_FILE`.
43 |
44 |
45 | ##### Improve the default `.env` output and support customizing the printer
46 |
47 | As you may have noticed in the above example, the prompt has been upgraded to read better, when `AUTOENV_VIEWER` is set to a non-empty variable.
48 |
49 | By default, `autoenv` will use the old authorization prompt to reduce disruption for current users that are used to the old prompt. Opt-in by setting `AUTOENV_VIEWER` to a non-empty value, like `cat`. Another good value is `less -N`.
50 |
51 | Thanks to @alissa-huskey! (#206)
52 |
53 | ##### Supports the XDG Base Directory Specification
54 |
55 | The [XDG Base Directory Specification](https://xdgbasedirectoryspecification.com) is now adhered to. Some details:
56 | - On a fresh install, both `AUTOENV_AUTH_FILE` and `AUTOENV_NOTAUTH_FILE` are written under `$HOME/.local/state/autoenv`
57 | - If `AUTOENV_AUTH_FILE` is already written under `$HOME`, then the new `AUTOENV_NOTAUTH_FILE` will also be written under there for consistency
58 | - For maximum backwards-compatability, files are not moved to the new location; the old locations can still be used
59 |
60 | ##### Document useful variables
61 |
62 | Before invoking your shell script, `autoenv` sets the following _environment variables_:
63 |
64 | - `AUTOENV_CUR_FILE` - The file being sourced
65 | - `AUTOENV_CUR_DIR` - Equivalent to `dirname "$AUTOENV_CUR_FILE"`
66 |
67 | These were added a while back in 988723d2e1f5d905e9fcedee7e236a3855185ad5, but were undocumented. Besides convenience, documenting it allows users to be confident that the feature will not be removed. I have also added the checking of these values to the test suite.
68 |
69 | ##### Prevent overriding `cd` with `AUTOENV_PRESERVE_CD`
70 |
71 | By default, `autoenv` runs:
72 |
73 | ```console
74 | cd() {
75 | autoenv_cd "${@}"
76 | }
77 | ```
78 |
79 | This would override any pre-existing `cd` function, making it a bit annoying to work around if a custom `cd` function is desired (and defined before `autoenv` is evaluated).
80 |
81 | Now, set `AUTOENV_PRESERVE_CD` to a non-empty string to prevent this behavior. `autoenv_cd` will still be exposed for invocation in custom `cd` functions.
82 |
83 | ### Fixes
84 |
85 | ##### Path prefix match accounts for path boundaries
86 |
87 | Before, when cding from a/b to a/bz, a/b/.env.leave would not be sourced. Path matching did not use forward slashes as a "cutoff" when testing if directories are different. Now, in the aforementioned situation, the file is properly sourced.
88 |
89 | Thanks to @tomtseng! (#238)
90 |
91 | ##### Fix `.env.leave` when sourcing from a subdirectory
92 |
93 | Let's say there exists the following directory structure:
94 |
95 | ```text
96 | ~/project/.env
97 | ~/project/.env.leave
98 | ~/project/src
99 | ```
100 |
101 | If the current directory is `~/project/src`, and `cd /` is invoked, `.env.leave` was previously not executed. Now it is.
102 |
103 | Thanks to @pashaosipyants! (#211)
104 |
105 | ##### Fix paths when installing through npm
106 |
107 | The npm installation instructions included an incorrect installation path, which would lead to errors if followed. Now, it includes the correct paths.
108 |
109 | Thanks to @wesleycoder! (#234)
110 |
111 | ### Other
112 |
113 | And some less noticable, but still notable improvements:
114 |
115 | - Improve installation instructions
116 | - Made instructions more clear for the different operating systems and shells
117 | - Add automated install script under scripts/install.sh
118 | - Add documentation for uninstalling and updating
119 | - Various refactoring
120 | - Implement some tests in Bats
121 |
122 | ## [v0.3.0] - 2021-09-05
123 |
124 | ### Fixed
125 |
126 | - Leave `$OLDPWD` intact (#141)
127 | - `AUTOENV_CUR_DIR` contains leading double quote (#150)
128 | - Prevent any alias usage (#144)
129 | - Broken mountpoint detection (#151)
130 | - Add `AUTOENV_ASSUME_YES` (#162)
131 | - Execute `.env.leave` when leaving directory (#167)
132 | - Ensure parent directory of `AUTOENV_AUTH_FILE` exists (#201)
133 | - Improve platform compatibility (#174, #176, #202)
134 |
135 | ## [v0.2.1] - 2016-10-18
136 |
137 | ### Fixed
138 |
139 | - Remove debug output (#126)
140 | - Paths with spaces on dash
141 | - Custom names for .env (#109)
142 | - Usage of double slashes (#125)
143 | - Infinite loop when symlinking across mountpoints (#133)
144 | - Don't allow chdir aliases
145 | - Mountpoint detection (#138 #139)
146 | - No more override of `$OLDPWD` (#141)
147 | - .env files at mountpoint are now being found (#146)
148 |
149 | ## [v0.2.0] - 2016-08-08
150 |
151 | ### Added
152 |
153 | - setup.py for pyPi
154 | - setup.py in the Makefile
155 | - Support for OS X
156 | - Support for the dash shell
157 | - Accept 'y' or 'Y' as answer
158 | - Expose `AUTOENV_CUR_FILE` and `AUTOENV_CUR_DIR`
159 |
160 | ### Fixed
161 |
162 | - Fix spaces in filenames
163 | - Strange grep behavior
164 | - Look for a .env file when activating autoenv
165 | - Fix sha1sum not being found
166 | - Support aliased cd
167 | - Require .env to be a regular file
168 | - autoenv now works with noclobber
169 | - Crash with zsh 5.1
170 |
171 | ### Changed
172 |
173 | - Don't run in mc
174 | - Updated readme
175 | - Export all variables
176 | - Rewrote tests
177 | - Follow .env files until the mountpoint
178 |
179 | ### Security
180 |
181 | - Add quotes everywhere in the shell script
182 | - Print hidden characters
183 |
184 | ## [v0.1.0] - 2012-02-15
185 |
186 | ### Added
187 |
188 | - .env files need approval now
189 |
190 | ### Fixed
191 |
192 | - Execution on zsh
193 |
194 | ### Changed
195 |
196 | - Put autoenv under a public license
197 |
198 | ## [v0.0.1] - 2012-02-13
199 |
200 | ### Added
201 |
202 | - Initial public version of autoenv
203 | - Allows executing .env files recursively
204 | - Makefile for testing
205 | - Unit tests with dtf
206 | - Travis file for testing
207 |
208 | [v0.0.1]: https://github.com/inishchith/autoenv/releases/tag/v0.0.1
209 | [v0.1.0]: https://github.com/inishchith/autoenv/releases/tag/v0.1.0
210 | [v0.2.0]: https://github.com/inishchith/autoenv/releases/tag/v0.2.0
211 | [v0.2.1]: https://github.com/inishchith/autoenv/releases/tag/v0.2.1
212 | [v0.3.0]: https://github.com/inishchith/autoenv/releases/tag/v0.3.0
213 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2012 Kenneth Reitz
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: test test-bats publish
2 |
3 | test:
4 | sh tests/test.sh
5 |
6 | test-bats:
7 | bats tests
8 |
9 | test2:
10 | @echo "=== AUTOENV TESTING SH ==="
11 | sh ./shelltestrunner.sh
12 | @echo "=== AUTOENV TESTING BASH ==="
13 | bash ./shelltestrunner.sh
14 | @echo "=== AUTOENV TESTING ZSH ==="
15 | zsh ./shelltestrunner.sh
16 |
17 | publish:
18 | npm publish
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Autoenv: Directory-based Environments 
2 |
3 | Magic per-project shell environments.
4 |
5 | ## What is it?
6 |
7 | If a directory contains an `.env` file, it will automatically be executed when you `cd` into it. And, if a directory contains an `.env.leave` file (and `AUTOENV_ENABLE_LEAVE` is a non-empty string), the file will automatically be executed when `cd`'ing away from the directory that contains that file.
8 |
9 | This is great for...
10 |
11 | - auto-activating virtualenvs
12 | - auto-deactivating virtualenvs
13 | - project-specific environment variables
14 | - making millions
15 |
16 | You can also nest envs within each other. How awesome is that!?
17 |
18 | When executing, autoenv, will walk up the directories until the mount
19 | point and execute all `.env` files beginning at the top.
20 |
21 | ## Usage
22 |
23 | Follow the white rabbit:
24 |
25 | ```sh
26 | $ echo "echo 'whoa'" > ./project/.env
27 | $ cd ./project
28 | whoa
29 | ```
30 |
31 | 
32 |
33 | ## Installation (automated)
34 |
35 | ```sh
36 | # with cURL
37 | curl -#fLo- 'https://raw.githubusercontent.com/hyperupcall/autoenv/main/scripts/install.sh' | sh
38 |
39 | # with wget
40 | wget --show-progress -o /dev/null -O- 'https://raw.githubusercontent.com/hyperupcall/autoenv/main/scripts/install.sh' | sh
41 | ```
42 |
43 | If you encounter some variant of a `curl: command not found` or `wget: command not found` error, please install either cURL or wget (with your package manager) and try again.
44 |
45 | ## Installation (manual)
46 |
47 | When installing manually, you first install autoenv with either Homebrew, npm, or Git. Then, you run a command to ensure autoenv is loaded when you open a terminal (this command depends on your [default shell](https://askubuntu.com/a/590901)).
48 |
49 | ### Installation Method
50 |
51 | Note that depending on your shell and operating system, you may need to write to `.zprofile` instead of `.zshrc`, or write to `.bash_profile` instead of `.bashrc` (or visa-versa).
52 |
53 | #### Using Homebrew
54 |
55 | Prefer this if you're running macOS. Homebrew [must be installed](https://brew.sh).
56 |
57 |
58 | Click to expand content
59 |
60 | First, download the [autoenv](https://formulae.brew.sh/formula/autoenv) homebrew formulae:
61 |
62 | ```sh
63 | $ brew install 'autoenv'
64 | ```
65 |
66 | Then, execute one of the following to ensure autoenv is loaded when you open a terminal:
67 |
68 | ```sh
69 | # For Zsh shell (on Linux or macOS)
70 | $ printf '%s\n' "source $(brew --prefix autoenv)/activate.sh" >> "${ZDOTDIR:-$HOME}/.zprofile"
71 |
72 | # For Bash shell (on Linux)
73 | $ printf '%s\n' "source $(brew --prefix autoenv)/activate.sh" >> ~/.bashrc
74 |
75 | # For Bash shell (on macOS)
76 | $ printf '%s\n' "source $(brew --prefix autoenv)/activate.sh" >> ~/.bash_profile
77 | ```
78 |
79 |
80 |
81 | #### Using npm
82 |
83 | Prefer this if you're running Linux or an unsupported version of macOS. npm [must be installed](https://nodejs.org/en/download) (usually through NodeJS).
84 |
85 |
86 | Click to expand content
87 |
88 | First, download the [@hyperupcall/autoenv](https://www.npmjs.com/package/@hyperupcall/autoenv) npm package:
89 |
90 | ```sh
91 | $ npm install -g '@hyperupcall/autoenv'
92 | ```
93 |
94 | Then, execute one of the following to ensure autoenv is loaded when you open a terminal:
95 |
96 | ```sh
97 | # For Zsh shell (on Linux or macOS)
98 | $ printf '%s\n' "source $(npm root -g)/@hyperupcall/autoenv/activate.sh" >> "${ZDOTDIR:-$HOME}/.zprofile"
99 |
100 | # For Bash shell (on Linux)
101 | $ printf '%s\n' "source $(npm root -g)/@hyperupcall/autoenv/activate.sh" >> ~/.bashrc
102 |
103 | # For Bash shell (on macOS)
104 | $ printf '%s\n' "source $(npm root -g)/@hyperupcall/autoenv/activate.sh" >> ~/.bash_profile
105 | ```
106 |
107 |
108 |
109 | #### Using Git
110 |
111 | Use this if you cannot install with Homebrew or npm.
112 |
113 |
114 | Click to expand content
115 |
116 | First, clone this repository:
117 |
118 | ```sh
119 | $ git clone 'https://github.com/hyperupcall/autoenv' ~/.autoenv
120 | ```
121 |
122 | Then, execute one of the following to ensure autoenv is loaded when you open a terminal:
123 |
124 | ```sh
125 | # For Zsh shell (on Linux or macOS)
126 | $ printf '%s\n' "source ~/.autoenv/activate.sh" >> "${ZDOTDIR:-$HOME}/.zprofile"
127 |
128 | # For Bash shell (on Linux)
129 | $ printf '%s\n' "source ~/.autoenv/activate.sh" >> ~/.bashrc
130 |
131 | # For Bash shell (on macOS)
132 | $ printf '%s\n' "source ~/.autoenv/activate.sh" >> ~/.bash_profile
133 | ```
134 |
135 |
136 |
137 | ## Configuration
138 |
139 | _Before_ `source`ing `activate.sh`, you can set the following variables:
140 |
141 | - `AUTOENV_AUTH_FILE`: Files authorized to be sourced; defaults to `~/.autoenv_authorized` if it exists, otherwise, `~/.local/state/autoenv/authorized_list`
142 | - `AUTOENV_NOTAUTH_FILE`: Files not authorized to be sourced; defaults to `~/.autoenv_not_authorized` if it exists, otherwise, `~/.local/state/autoenv/not_authorized_list`
143 | - `AUTOENV_ENV_FILENAME`: Name of the `.env` file; defaults to `.env`
144 | - `AUTOENV_LOWER_FIRST`: Set this variable to a non-empty string to flip the order of `.env` files executed
145 | - `AUTOENV_ENV_LEAVE_FILENAME`: Name of the `.env.leave` file; defaults to `.env.leave`
146 | - `AUTOENV_ENABLE_LEAVE`: Set this to a non-empty string in order to enable source env when leaving
147 | - `AUTOENV_ASSUME_YES`: Set this variable to a non-empty string to silently authorize the initialization of new environments
148 | - `AUTOENV_VIEWER`: Program used to display env files prior to authorization; defaults to `cat`
149 | - `AUTOENV_PRESERVE_CD`: Set this variable to a non-empty string to prevent the `cd` builtin from being overridden (to active autoenv, you must invoke `autoenv_init` within a `cd` function of your own)
150 |
151 | We recommend setting the following configuration variables:
152 |
153 | ```bash
154 | AUTOENV_ENABLE_LEAVE=yes
155 | AUTOENV_VIEWER=cat
156 | ```
157 |
158 | These options are not set by default as to conform to the expectations of backwards-compatible behavior.
159 |
160 | ### API
161 |
162 | Inside the `.env` file, two _environment variables_ can be accessed:
163 |
164 | - `AUTOENV_CUR_FILE` - The file being sourced
165 | - `AUTOENV_CUR_DIR` - Equivalent to `dirname "$AUTOENV_CUR_FILE"`
166 |
167 | ## Shells
168 |
169 | autoenv is tested on:
170 |
171 | - Bash
172 | - Zsh
173 | - Dash
174 | - Fish is supported by [autoenv_fish](https://github.com/loopbit/autoenv_fish)
175 | - More to come
176 |
177 | ## Disclaimer
178 |
179 | Autoenv overrides `cd` (unless `AUTOENV_PRESERVE_CD` is set to a non-empty string). If you already do this, invoke `autoenv_init` within your custom `cd` after sourcing `activate.sh`.
180 |
181 | If you define a `cd` alias, `autoenv` will (properly) show an error except when using Zsh. We recommend removing any aliases to `cd`! (`unalias cd`).
182 |
183 | If you are using `dash`, `autoenv` will work. However, `dash` does not support `builtin`. As a result, in `dash`, `autoenv` invokes `chdir` instead of `cd` to prevent infinite loops.
184 |
185 | Autoenv can be disabled via `unset -f cd` if you experience I/O issues with certain file systems, particularly those that are FUSE-based (such as `smbnetfs`).
186 |
187 | ## Other info
188 |
189 | To uninstall autoenv, see [`./docs/uninstall.md`](./docs/uninstall.md).
190 |
191 | To update autoenv, see [`./docs/updating.md`](./docs/updating.md).
192 |
193 | ## Attributions
194 |
195 | Autoenv was originally created by [@kennethreitz](https://github.com/kennethreitz). Later, ownership was transfered to [@inishchith](https://github.com/inishchith). As of August 22nd, 2021, Edwin Kofler ([@hyperupcall](https://github.com/hyperupcall)) owns and maintains the project.
196 |
--------------------------------------------------------------------------------
/activate.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 | # shellcheck disable=SC2216,SC3043
3 |
4 | if [ -n "${AUTOENV_AUTH_FILE:-}" ]; then
5 | :
6 | elif [ -f "$HOME/.autoenv_authorized" ]; then
7 | AUTOENV_AUTH_FILE="$HOME/.autoenv_authorized"
8 | else
9 | _autoenv_state_dir="$XDG_STATE_HOME"
10 | case $_autoenv_state_dir in
11 | /*) AUTOENV_AUTH_FILE="$_autoenv_state_dir/autoenv/authorized_list" ;;
12 | *) AUTOENV_AUTH_FILE="$HOME/.local/state/autoenv/authorized_list" ;;
13 | esac
14 | unset -v _autoenv_state_dir
15 | fi
16 | if [ -n "${AUTOENV_NOTAUTH_FILE:-}" ]; then
17 | :
18 | elif [ -f "$HOME/.autoenv_authorized" ]; then
19 | # If `.autoenv_authorized` is in home, don't suprise the user by using XDG Base Dir.
20 | AUTOENV_NOTAUTH_FILE="$HOME/.autoenv_not_authorized"
21 | elif [ -f "$HOME/.autoenv_not_authorized" ]; then
22 | # Ensure file in ~/ is used, even if the authorized file has been moved or deleted.
23 | AUTOENV_NOTAUTH_FILE="$HOME/.autoenv_not_authorized"
24 | else
25 | _autoenv_state_dir="$XDG_STATE_HOME"
26 | case $_autoenv_state_dir in
27 | /*) AUTOENV_NOTAUTH_FILE="$_autoenv_state_dir/autoenv/not_authorized_list" ;;
28 | *) AUTOENV_NOTAUTH_FILE="$HOME/.local/state/autoenv/not_authorized_list" ;;
29 | esac
30 | unset -v _autoenv_state_dir
31 | fi
32 | AUTOENV_ENV_FILENAME="${AUTOENV_ENV_FILENAME:-.env}"
33 | AUTOENV_ENV_LEAVE_FILENAME="${AUTOENV_ENV_LEAVE_FILENAME:-.env.leave}"
34 | : ${AUTOENV_VIEWER:=}
35 | # AUTOENV_ENABLE_LEAVE
36 |
37 | __autoenv_use_color() {
38 | if [ ${NO_COLOR+x} ]; then
39 | return 1
40 | fi
41 | case ${FORCE_COLOR:-} in
42 | 1|2|3) return 0 ;;
43 | 0) return 1 ;;
44 | esac
45 | if [ "$TERM" = 'dumb' ]; then
46 | return 1
47 | fi
48 | if [ -t 1 ]; then
49 | return 0
50 | fi
51 |
52 | return 1
53 | }
54 |
55 | # @description Prints a user message to standard output
56 | # @internal
57 | _autoenv_print() {
58 | local title="${1}" color="${2}" text="${3}"
59 | # shellcheck disable=SC2059
60 | if __autoenv_use_color; then
61 | \printf "\033[${color}m[${title}]\033[0m ${text}"
62 | else
63 | \printf "[${title}] ${text}"
64 | fi
65 | }
66 |
67 | # @description Prints a horizontal line
68 | # @args $1: title text to print near the beginning of the line
69 | # @internal
70 | _autoenv_draw_line() {
71 | local text="${1:-}" char="-" width=${COLUMNS:-80} margin=3 line
72 |
73 | if [ -n "${text}" ]; then
74 | text="--- ${text} "
75 | fi
76 |
77 | width=$((width - ${#text} - margin))
78 | line=$(\printf '%*s\n' ${width} | \command tr " " "${char}")
79 |
80 | if __autoenv_use_color; then
81 | \printf "\033[1m%s%s\033[0m\n" "${text}" "${line}"
82 | else
83 | \printf "%s%s\n" "${text}" "${line}"
84 | fi
85 | }
86 |
87 | # @description Main initialization function
88 | # @internal
89 | autoenv_init() {
90 | if [ -n "${AUTOENV_ENABLE_LEAVE:-}" ]; then
91 | autoenv_leave "$@"
92 | fi
93 |
94 | local _mountpoint _pwd
95 | _mountpoint="$(\command df -P "${PWD}" | \command tail -n 1 | \command awk '$0=$NF')"
96 | _pwd=$(\echo "${PWD}" | \command sed -E 's:/+:/:g') # Removes double slashes. (see #125)
97 |
98 | # Discover all files that we need to source.
99 | local _files
100 | _files=$(
101 | \command -v chdir >/dev/null 2>&1 && \chdir "${_pwd}" || \builtin cd "${_pwd}"
102 | _hadone=''
103 | while :; do
104 | _file="$(\pwd -P)/${AUTOENV_ENV_FILENAME}"
105 | if [ -f "${_file}" ]; then
106 | if [ -z "${_hadone}" ]; then
107 | \printf %s "${_file}"
108 | _hadone='1'
109 | else
110 | \printf %s "
111 | ${_file}"
112 | fi
113 | fi
114 | [ "$(\pwd -P)" = "${_mountpoint}" ] && \break
115 | [ "$(\pwd -P)" = "/" ] && \break
116 | \command -v chdir >/dev/null 2>&1 && \chdir "$(\pwd -P)/.." || \builtin cd "$(\pwd -P)/.."
117 | done
118 | )
119 |
120 | # ZSH: Use traditional for loop
121 | if [ -n "${ZSH_VERSION:-}" ]; then
122 | \setopt shwordsplit >/dev/null 2>&1
123 | fi
124 |
125 | # Custom IFS
126 | origIFS="${IFS}"
127 | IFS='
128 | '
129 |
130 | \set -f
131 | # Turn around the env files order if needed
132 | local _orderedfiles=''
133 | if [ -z "${AUTOENV_LOWER_FIRST:-}" ]; then
134 | for _file in ${_files}; do
135 | _orderedfiles="${_file}
136 | ${_orderedfiles}"
137 | done
138 | else
139 | _orderedfiles="${_files}"
140 | fi
141 | # Execute the env files
142 | for _file in ${_orderedfiles}; do
143 | _autoenv_check_authz_and_run "${_file}"
144 | done
145 | \unset -v _orderedfiles
146 | IFS="${origIFS}"
147 | \set +f
148 |
149 | # ZSH: Unset shwordsplit
150 | if [ -n "${ZSH_VERSION:-}" ]; then
151 | \unsetopt shwordsplit >/dev/null 2>&1
152 | fi
153 | }
154 |
155 | # @description Checks the expected hash entry of the file
156 | # @internal
157 | autoenv_hashline() {
158 | local _envfile="${1}" _hash
159 | _hash=$(autoenv_shasum "${_envfile}" | \command cut -d' ' -f 1)
160 | \printf '%s\n' "${_envfile}:${_hash}"
161 | }
162 |
163 | # @description Source an env file if is able to do so
164 | # @internal
165 | _autoenv_check_authz_and_run() {
166 | local _envfile="${1}" _hash
167 | _hash=$(autoenv_hashline "${_envfile}")
168 |
169 | \command mkdir -p -- "$(\command dirname "${AUTOENV_AUTH_FILE}")" "$(\command dirname "${AUTOENV_NOTAUTH_FILE}")"
170 | \command touch -- "${AUTOENV_AUTH_FILE}" "${AUTOENV_NOTAUTH_FILE}"
171 | if \command grep -q "${_hash}" -- "${AUTOENV_AUTH_FILE}"; then
172 | autoenv_source "${_envfile}"
173 | \return 0
174 | elif \command grep -q "${_hash}" -- "${AUTOENV_NOTAUTH_FILE}"; then
175 | \return 0
176 | fi
177 |
178 | # Don't ask for permission if "assume yes" is switched on
179 | if [ -n "${AUTOENV_ASSUME_YES:-}" ]; then
180 | autoenv_authorize_env "${_envfile}"
181 | autoenv_source "${_envfile}"
182 | \return 0
183 | fi
184 |
185 | if [ -n "${MC_SID:-}" ]; then # Make sure mc is not running
186 | \return 0
187 | fi
188 |
189 | if [ -z "$AUTOENV_VIEWER" ]; then
190 | \echo "autoenv:"
191 | \echo "autoenv: WARNING:"
192 | \printf '%s\n' "autoenv: This is the first time you are about to source ${_envfile}":
193 | \echo "autoenv:"
194 | \echo "autoenv: --- (begin contents) ---------------------------------------"
195 | \cat -e "${_envfile}" | LC_ALL=C \command sed 's/.*/autoenv: &/'
196 | \echo "autoenv:"
197 | \echo "autoenv: --- (end contents) -----------------------------------------"
198 | \echo "autoenv:"
199 | \printf "%s" "autoenv: Are you sure you want to allow this? (y/N/D) " # Keep (y/N/D) for old UI consistency.
200 | else
201 | _autoenv_print 'autoenv' 36 'New or modified env file detected\n'
202 | _autoenv_draw_line "Contents of \"${_envfile##*/}\""
203 | local ofs="${IFS}"
204 | IFS=" "
205 | $AUTOENV_VIEWER "${_envfile}"
206 | IFS="${ofs}"
207 | _autoenv_draw_line
208 | _autoenv_print 'autoenv' 36 "Authorize this file? (y/n/d) "
209 | fi
210 | \read -r answer
211 | if [ "${answer}" = "y" ] || [ "${answer}" = "Y" ]; then
212 | autoenv_authorize_env "${_envfile}"
213 | autoenv_source "${_envfile}"
214 | elif [ "${answer}" = "d" ] || [ "${answer}" = "D" ]; then
215 | autoenv_unauthorize_env "${_envfile}"
216 | fi
217 | }
218 |
219 | # @description Mark an env file as able to be sourced
220 | # @internal
221 | autoenv_deauthorize_env() {
222 | local _envfile="${1}"
223 | \command cp -- "${AUTOENV_AUTH_FILE}" "${AUTOENV_AUTH_FILE}.tmp"
224 | \command grep -Gv "${_envfile}:" -- "${AUTOENV_AUTH_FILE}.tmp" >| "${AUTOENV_AUTH_FILE}"
225 | \command rm -- "${AUTOENV_AUTH_FILE}.tmp" 2>/dev/null || :
226 | }
227 |
228 | # @description Mark an env file as not able to be sourced
229 | # @internal
230 | autoenv_unauthorize_env() {
231 | local _envfile="$1"
232 | autoenv_deauthorize_env "$_envfile"
233 | autoenv_hashline "$_envfile" >> "$AUTOENV_NOTAUTH_FILE"
234 | }
235 |
236 | # @description Mark an env file as able to be sourced
237 | # @internal
238 | autoenv_authorize_env() {
239 | local _envfile="${1}"
240 | autoenv_deauthorize_env "${_envfile}"
241 | autoenv_hashline "${_envfile}" >> "${AUTOENV_AUTH_FILE}"
242 | }
243 |
244 | # @description Actually source a file
245 | # @internal
246 | autoenv_source() {
247 | AUTOENV_CUR_DIR="$(\command dirname "${1}")"
248 | export AUTOENV_CUR_FILE="${1}" AUTOENV_CUR_DIR
249 | case $- in
250 | *a*) ;;
251 | *) \set -a; local __autoenv_set_allexport=yes ;;
252 | esac
253 |
254 | # shellcheck disable=SC1090
255 | . "${1}"
256 |
257 | if [ "${__autoenv_set_allexport:-}" = 'yes' ]; then
258 | \set +a
259 | fi
260 | \unset -v AUTOENV_CUR_FILE AUTOENV_CUR_DIR
261 | }
262 |
263 | # @description Function to override the 'cd' builtin
264 | autoenv_cd() {
265 | local _pwd="${PWD}"
266 | if \command -v chdir >/dev/null 2>&1 && \chdir "${@}" || \builtin cd "${@}"; then
267 | autoenv_init "${_pwd}"
268 | \return 0
269 | else
270 | \return "${?}"
271 | fi
272 | }
273 |
274 | # @description Cleanup autoenv
275 | autoenv_leave() {
276 | local from_dir="${*}" to_dir
277 | to_dir=$(\echo "${PWD}" | \command sed -E 's:/+:/:g')
278 |
279 | # Discover all files that we need to source.
280 | local _files
281 | _files=$(
282 | \command -v chdir >/dev/null 2>&1 && \chdir "${from_dir}" || \builtin cd "${from_dir}"
283 | _hadone=''
284 | while [ "$PWD" != "" ] && [ "$PWD" != "/" ]; do
285 | case $to_dir/ in
286 | $PWD/*)
287 | \break
288 | ;;
289 | *)
290 | _file="$PWD/${AUTOENV_ENV_LEAVE_FILENAME}"
291 | if [ -f "${_file}" ]; then
292 | if [ -z "${_hadone}" ]; then
293 | \printf %s "${_file}"
294 | _hadone='1'
295 | else
296 | \printf %s "
297 | ${_file}"
298 | fi
299 | fi
300 | \command -v chdir >/dev/null 2>&1 && \chdir "$(\pwd)/.." || \builtin cd "$PWD/.."
301 | ;;
302 | esac
303 | done
304 | )
305 |
306 | # ZSH: Use traditional for loop
307 | if [ -n "${ZSH_VERSION:-}" ]; then
308 | \setopt shwordsplit >/dev/null 2>&1
309 | fi
310 |
311 | # Custom IFS
312 | origIFS="${IFS}"
313 | IFS='
314 | '
315 |
316 | # Execute the env files
317 | \set -f
318 | for _file in ${_files}; do
319 | _autoenv_check_authz_and_run "${_file}"
320 | done
321 | IFS="${origIFS}"
322 | \set +f
323 |
324 | # ZSH: Unset shwordsplit
325 | if [ -n "${ZSH_VERSION:-}" ]; then
326 | \unsetopt shwordsplit >/dev/null 2>&1
327 | fi
328 | }
329 |
330 | # Set Zsh option to prevent errors when "cd" is already an alias.
331 | # shellcheck disable=SC3010
332 | if [ -n "${ZSH_VERSION:-}" ] && [[ ! -o aliasfuncdef ]]; then
333 | __autoenv_unset_aliasfuncdef=yes
334 | \setopt ALIAS_FUNC_DEF 2>/dev/null
335 | fi
336 |
337 | # @description Run to automatically replace the cd builtin with our improved one
338 | enable_autoenv() {
339 | if [ -z "${AUTOENV_PRESERVE_CD:-}" ]; then
340 | cd() {
341 | autoenv_cd "${@}"
342 | }
343 | fi
344 |
345 | cd "${PWD}"
346 | }
347 |
348 | if [ "${__autoenv_unset_aliasfuncdef:-}" = 'yes' ]; then
349 | \unsetopt ALIAS_FUNC_DEF 2>/dev/null
350 | \unset -v __autoenv_unset_aliasfuncdef
351 | fi
352 |
353 | # If some shasum exists, specifically use it. Otherwise, do not enable autoenv.
354 | if \command -v gsha1sum >/dev/null 2>&1; then
355 | autoenv_shasum() {
356 | gsha1sum "${@}"
357 | }
358 | enable_autoenv "$@"
359 | elif \command -v sha1sum >/dev/null 2>&1; then
360 | autoenv_shasum() {
361 | sha1sum "${@}"
362 | }
363 | enable_autoenv "$@"
364 | elif \command -v shasum >/dev/null 2>&1; then
365 | autoenv_shasum() {
366 | shasum "${@}"
367 | }
368 | enable_autoenv "$@"
369 | else
370 | _autoenv_print 'autoenv error' 31 "can not locate a compatible shasum binary; not enabling\n" >&2
371 | fi
372 |
--------------------------------------------------------------------------------
/aur/autoenv-git/PKGBUILD:
--------------------------------------------------------------------------------
1 | # Maintainer: hyperupcall
2 |
3 | pkgname=autoenv-git
4 | pkgver=0.3.0
5 | pkgrel=1
6 | pkgdesc='Directory based enviroments'
7 | arch=('any')
8 | url='https://github.com/hyperupcall/autoenv'
9 | license=('MIT')
10 | source=("$pkgname"::'git+https://github.com/hyperupcall/autoenv.git')
11 | sha256sums=('SKIP')
12 | depends=('bash')
13 | optdepends=('zsh: if preferred over bash')
14 | makedepends=('git')
15 | conflicts=('autoenv')
16 |
17 | pkgver() {
18 | cd "$pkgname" || exit
19 |
20 | set -o pipefail
21 | git describe --tags --long | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
22 | }
23 |
24 | package() {
25 | cd "$pkgname" || exit
26 |
27 | install -D -m755 activate.sh "${pkgdir}/usr/share/${pkgname}/activate.sh"
28 | install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
29 | }
30 |
--------------------------------------------------------------------------------
/aur/autoenv/PKGBUILD:
--------------------------------------------------------------------------------
1 | # Maintainer: hyperupcall
2 |
3 | pkgname=autoenv
4 | pkgver=0.3.0
5 | pkgrel=1
6 | pkgdesc='Directory-based enviroments'
7 | arch=('any')
8 | url='https://github.com/hyperupcall/autoenv'
9 | license=('MIT')
10 | source=("$pkgname"::'git+https://github.com/hyperupcall/autoenv.git#commit=025e52fbf033cc094943febec71e2ad81a5de84f')
11 | sha256sums=('SKIP')
12 | depends=('bash')
13 | optdepends=('zsh: if preferred over bash')
14 | makedepends=('git')
15 | conflicts=('autoenv-git')
16 |
17 | package() {
18 | cd "$pkgname" || exit
19 |
20 | install -D -m755 './activate.sh' "${pkgdir}/etc/profile.d/autoenv_activate.sh"
21 | install -D -m644 './LICENSE' "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
22 | }
23 |
--------------------------------------------------------------------------------
/autoenv.plugin.zsh:
--------------------------------------------------------------------------------
1 | # Standarized $0 handling, following:
2 | # https://z-shell.github.io/zsh-plugin-assessor/Zsh-Plugin-Standard
3 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
4 | 0="${${(M)0:#/*}:-$PWD/$0}"
5 |
6 | . ${0:h}/activate.sh
7 |
--------------------------------------------------------------------------------
/docs/uninstall.md:
--------------------------------------------------------------------------------
1 | # Uninstall
2 |
3 | The uninstallation procedure depends on your installation method.
4 |
5 | ## Method
6 |
7 | ### Homebrew
8 |
9 | If you installed autoenv with homebrew, run the following:
10 |
11 | ```sh
12 | $ brew uninstall 'autoenv'
13 | ```
14 |
15 | ### With npm
16 |
17 | If you installed autoenv with npm, run the following:
18 |
19 | ```sh
20 | $ npm uninstall -g '@hyperupcall/autoenv'
21 | ```
22 |
23 | ### With Git
24 |
25 | If you installed autoenv with Git, run the following:
26 |
27 | ```sh
28 | rm -rf ~/.autoenv
29 | ```
30 |
31 | ## Post Cleanup
32 |
33 | After uninstalling autoenv, your shell may still contain parts of autoenv in memory. To prevent executing these parts, run the following in each open terminal:
34 |
35 | ```sh
36 | unset -f 'cd'
37 | ```
38 |
39 | Note that the `-f` is important. This removes autoenv's custom `cd` _function_ and allows the shell to use its own `cd` _builtin_ instead.
40 |
--------------------------------------------------------------------------------
/docs/updating.md:
--------------------------------------------------------------------------------
1 | # Updating
2 |
3 | Keeping autoenv up to date depends on your installation method:
4 |
5 | ## Method
6 |
7 | ### Homebrew
8 |
9 | If you installed autoenv with homebrew, run the following:
10 |
11 | ```sh
12 | $ brew update 'autoenv'
13 | ```
14 |
15 | ### With npm
16 |
17 | If you installed autoenv with npm, run the following:
18 |
19 | ```sh
20 | $ npm update -g '@hyperupcall/autoenv'
21 | ```
22 |
23 | ### With Git
24 |
25 | If you installed autoenv with Git, run the following:
26 |
27 | ```sh
28 | git -C ~/.autoenv pull
29 | ```
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@hyperupcall/autoenv",
3 | "version": "0.4.0",
4 | "description": "Magic per-project shell environments",
5 | "author": "Edwin Kofler (https://edwinkofler.com)",
6 | "license": "MIT",
7 | "files": [
8 | "activate.sh"
9 | ],
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/hyperupcall/autoenv.git"
13 | },
14 | "homepage": "https://github.com/hyperupcall/autoenv#readme",
15 | "bugs": {
16 | "url": "https://github.com/hyperupcall/autoenv/issues",
17 | "email": "edwin@kofler.dev"
18 | },
19 | "keywords": [
20 | "autoenv",
21 | "shell"
22 | ],
23 | "devDependencies": {
24 | "@hyperupcall/bats-all": "^5.1.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | set -e
3 |
4 | note() {
5 | printf '%s\n' "install.sh: $1"
6 | }
7 |
8 | # shellcheck disable=SC2088
9 | if command -v brew >/dev/null 2>&1; then
10 | brew install 'autoenv'
11 | dot_sh_file="'$(brew --prefix autoenv)/activate.sh'"
12 | elif command -v npm >/dev/null 2>&1; then
13 | npm install -g '@hyperupcall/autoenv'
14 | dot_sh_file="'$(npm root -g)/@hyperupcall/autoenv/activate.sh'"
15 | elif command -v git >/dev/null 2>&1; then
16 | git clone 'https://github.com/hyperupcall/autoenv' ~/.autoenv
17 | dot_sh_file="~/.autoenv/activate.sh"
18 | else
19 | printf '%s\n' "Failed to install autoenv. Please install 'brew', 'npm', or 'git' first." >&2
20 | exit 1
21 | fi
22 |
23 | # Install for zsh
24 | if command -v zsh >/dev/null 2>&1; then
25 | zprofile="${ZDOTDIR:-$HOME}/.zprofile"
26 | zlogin="${ZDOTDIR:-$HOME}/.zlogin"
27 | zshrc="${ZDOTDIR:-$HOME}/.zshrc"
28 |
29 | if [ -f "$zprofile" ]; then
30 | note "appending to file: $zprofile"
31 | printf '%s\n' "source $dot_sh_file" >> "$zprofile"
32 | elif [ -f "$zlogin" ]; then
33 | note "appending to file: $zlogin"
34 | printf '%s\n' "source $dot_sh_file" >> "$zlogin"
35 | fi
36 |
37 | if [ -f "$zshrc" ]; then
38 | note "appending to file: $zshrc"
39 | printf '%s\n' "source $dot_sh_file" >> "$zshrc"
40 | else
41 | note "creating file: $zshrc"
42 | printf '%s\n' "source $dot_sh_file" >> "$zshrc"
43 | fi
44 | fi
45 |
46 | # Install for bash
47 | if command -v bash >/dev/null 2>&1; then
48 | if [ -f ~/.bash_profile ]; then
49 | note "appending to file: ~/.bash_profile"
50 | printf '%s\n' "source $dot_sh_file" >> ~/.bash_profile
51 | elif [ -f ~/.bash_login ]; then
52 | note "appending to file: ~/.bash_login"
53 | printf '%s\n' "source $dot_sh_file" >> ~/.bash_login
54 | fi
55 |
56 | if [ -f ~/.bashrc ]; then
57 | note "appending to file: ~/.bashrc"
58 | printf '%s\n' "source $dot_sh_file" >> ~/.bashrc
59 | else
60 | note "creating file: ~/.bashrc"
61 | printf '%s\n' "source $dot_sh_file" >> ~/.bashrc
62 | fi
63 | fi
64 |
65 | note 'DONE! Installation successfull!'
66 |
--------------------------------------------------------------------------------
/shelltestrunner.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | # Until https://github.com/hyperupcall/shelltest gets a release,
4 | # I've opted to manually create a test runner (using the same
5 | # interface)
6 |
7 | t_is_function() {
8 | if ! __tmp=$(type "$1" 2>/dev/null); then
9 | return 1
10 | fi
11 |
12 | # Most shells have a single line 'my_fn is a function'. In Bash,
13 | # the rest of the function is printed. In Zsh, it says 'my_fn is
14 | # a shell function'
15 | case $__tmp in
16 | "$1 is a function"*) return 0 ;;
17 | "$1 is a shell function"*) return 0 ;;
18 | esac
19 |
20 | return 1
21 | }
22 |
23 | t_assert() {
24 | if "$@"; then :; else
25 | printf '\033[41m%s\033[0m\n: %s' "Error" "Execution of command '$*' failed with exitcode $?" >&2
26 | return 1
27 | fi
28 | }
29 |
30 | main() {
31 | set -e
32 |
33 | printf '%s\n' "Sourcing api.sh"
34 | setup_file() { :; }
35 | teardown_file() { :; }
36 | setup() { :; }
37 | teardown() { :; }
38 | source ./shelltests/api.sh
39 | setup_file
40 | for fn in test_has_defined_functions; do
41 | printf '%s\n' "Running: $fn"
42 | setup
43 | "$fn"
44 | teardown
45 | done
46 | teardown_file
47 | printf '%s\n\n'
48 |
49 |
50 | printf '%s\n' "Sourcing cd.sh"
51 | setup_file() { :; }
52 | teardown_file() { :; }
53 | setup() { :; }
54 | teardown() { :; }
55 | source ./shelltests/cd.sh
56 | setup_file
57 | for fn in test_cd_noenv test_cd_dir test_cd_subdir test_cd_dir_and_subdir test_cd_dir_and_subdir_spaces test_cd_dir_and_subdir_colons; do
58 | printf '%s\n' "Running: $fn"
59 | setup
60 | "$fn"
61 | teardown
62 | done
63 | teardown_file
64 | printf '%s\n\n'
65 |
66 | printf '%s\n' "Sourcing env.sh"
67 | setup_file() { :; }
68 | teardown_file() { :; }
69 | setup() { :; }
70 | teardown() { :; }
71 | source ./shelltests/env.sh
72 | setup_file
73 | for fn in test_AUTOENV_ENV_FILENAME_works test_AUTOENV_ENV_FILENAME_works2; do
74 | printf '%s\n' "Running: $fn"
75 | setup
76 | "$fn"
77 | teardown
78 | done
79 | teardown_file
80 | }
81 | main "$@"
82 |
--------------------------------------------------------------------------------
/shelltests/api.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | setup_file() {
4 | export AUTOENV_ASSUME_YES='yes'
5 | . ./activate.sh
6 | }
7 |
8 | # The following functions must exist for API stability
9 | test_has_defined_functions() {
10 | t_is_function 'enable_autoenv'
11 | t_is_function 'autoenv_init'
12 | }
13 |
--------------------------------------------------------------------------------
/shelltests/cd.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | setup_file() {
4 | export AUTOENV_ASSUME_YES='yes'
5 | . ./activate.sh
6 | }
7 |
8 | # TODO: remove when shelltest uses tempdirs
9 | teardown_file() {
10 | rm -rf './dir' './d ir' './d:ir'
11 | }
12 |
13 | setup() {
14 | rm -rf './dir' './d ir' './d:ir'
15 | }
16 |
17 |
18 | test_cd_noenv() {
19 | mkdir -p './dir'
20 |
21 | output=$(cd './dir')
22 | t_assert [ -z "$output" ]
23 | }
24 |
25 | test_cd_dir() {
26 | mkdir -p './dir'
27 | printf '%s\n' "printf '%s\n' 'something'" > './dir/.env'
28 |
29 | output=$(cd './dir')
30 | t_assert [ "$output" = 'something' ]
31 | }
32 |
33 | test_cd_subdir() {
34 | mkdir -p './dir/subdir'
35 | printf '%s\n' "printf '%s\n' 'something2'" > './dir/.env'
36 |
37 | output=$(cd './dir/subdir')
38 | t_assert [ "$output" = 'something2' ]
39 | }
40 |
41 | test_cd_dir_and_subdir() {
42 | mkdir -p './dir/subdir'
43 |
44 | printf '%s\n' "printf '%s\n' 'sierra'" > './dir/.env'
45 | printf '%s\n' "printf '%s\n' 'tango'" > './dir/subdir/.env'
46 |
47 | output=$(cd './dir/subdir')
48 | t_assert [ "$output" = 'sierra
49 | tango' ]
50 | }
51 |
52 | test_cd_dir_and_subdir_spaces() {
53 | mkdir -p './d ir/s ubdir'
54 |
55 | printf '%s\n' "printf '%s\n' 'sierra'" > './d ir/.env'
56 | printf '%s\n' "printf '%s\n' 'tango'" > './d ir/s ubdir/.env'
57 |
58 | output=$(cd './d ir/s ubdir')
59 | t_assert [ "$output" = 'sierra
60 | tango' ]
61 | }
62 |
63 | test_cd_dir_and_subdir_colons() {
64 | mkdir -p './d:ir/s:ubdir'
65 |
66 | printf '%s\n' "printf '%s\n' 'sierra'" > './d:ir/.env'
67 | printf '%s\n' "printf '%s\n' 'tango'" > './d:ir/s:ubdir/.env'
68 |
69 | output=$(cd './d:ir/s:ubdir')
70 | t_assert [ "$output" = 'sierra
71 | tango' ]
72 | }
73 |
--------------------------------------------------------------------------------
/shelltests/env.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | setup_file() {
4 | export AUTOENV_ASSUME_YES='yes'
5 | . ./activate.sh
6 | }
7 |
8 | # TODO: remove when shelltest uses tempdirs
9 | teardown_file() {
10 | rm -rf './dir' './d ir' './d:ir'
11 | }
12 |
13 | setup() {
14 | rm -rf './dir' './d ir' './d:ir'
15 | }
16 |
17 | test_AUTOENV_ENV_FILENAME_works() {
18 | AUTOENV_ENV_FILENAME='o ther'
19 |
20 | mkdir -p './dir'
21 |
22 | printf '%s\n' "printf '%s\n' 'WOOF'" > './dir/o ther'
23 |
24 | output=$(cd './dir')
25 | t_assert [ "$output" = 'WOOF' ]
26 | }
27 |
28 | test_AUTOENV_ENV_FILENAME_works2() {
29 | AUTOENV_ENV_FILENAME='o ther'
30 |
31 | mkdir -p './dir'
32 |
33 | printf '%s\n' "printf '%s\n' 'WOOF'" > './dir/.env'
34 |
35 | output=$(cd './dir')
36 | t_assert [ "$output" = '' ]
37 | }
38 |
--------------------------------------------------------------------------------
/tests/functions:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | # Calls command, checks return code and output
4 | # Call: patterntest [command] [output pattern]
5 | patterntest() {
6 | out=$(eval "${1}")
7 | ret="$?"
8 | if [ -z ${ret} ] || [ ${ret} -ne 0 ]; then
9 | echo "Call completed with exit code ${ret}."
10 | exit 1
11 | fi
12 | echo "Output was:"
13 | echo "${out}"
14 | # Pattern test
15 | if ! printf '%s\n' "${out}" | grep -q "${2}" ; then
16 | echo "Output did not match pattern ${2}"
17 | exit 1
18 | fi
19 | }
20 |
--------------------------------------------------------------------------------
/tests/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | has_cmd() {
4 | command -v -- "$1" >/dev/null 2>&1
5 | }
6 |
7 | # Check if all commands exist
8 | for cmd in bash zsh dash; do
9 | if ! has_cmd "$cmd"; then
10 | echo ":: This test requires the ${cmd} executable."
11 | exit 1
12 | fi
13 | done
14 |
15 | MKTEMP=$(command -v mktemp)
16 | READLINK=$(command -v readlink)
17 | if [ "$(uname)" = "Darwin" ]; then
18 | for cmd in gmktemp greadlink; do
19 | if ! has_cmd "$cmd"; then
20 | echo ":: This test requires the ${cmd} executable."
21 | exit 1
22 | fi
23 | done
24 | MKTEMP=gmktemp
25 | READLINK=greadlink
26 | fi
27 |
28 | # Settings
29 | shells='bash:bash --noprofile --norc|zsh:zsh|sh:dash' # Shells to test. Shells separated by |, name/executable by :
30 |
31 | # Global variables
32 | TMPDIR='' # Global so we can react when the script fails
33 | basedir=$("$READLINK" -f "$(dirname "$0")") # So we can find our tests
34 | oldpwd=$PWD # So we can come back after testing
35 | export ZDOTDIR='/dev/null' # Don't use default ZSH files
36 |
37 | # Discover tests
38 | tests=''
39 | for file in $(find "${basedir}" -maxdepth 1 -type f -name 'test_*.sh'); do
40 | tests="${tests}|$(basename "$file" .sh)"
41 | done
42 | tests="${tests#|}"
43 |
44 | # Handle test errors
45 | fail() {
46 | echo "Fail."
47 | echo ":: Output of last test:"
48 | echo
49 | cd "${oldpwd}"
50 | cat "${basedir}/lasttest.log"
51 | test -z "${TMPDIR}" || rm -rf "${TMPDIR}"
52 | }
53 | trap fail EXIT INT TERM
54 | set -e
55 |
56 | export ACTIVATE_SH="${oldpwd}/activate.sh"
57 | export FUNCTIONS="${basedir}/functions"
58 |
59 | # Execute each test for each shell
60 | IFS='|'
61 | for shell in ${shells}; do
62 | for current_test in ${tests}; do
63 | # Prepare this test
64 | printf %s ":: Running ${current_test} for $(echo "${shell}" | cut -d':' -f1)..."
65 | TMPDIR=$("$MKTEMP" -dp "${basedir}" "${current_test}.XXXXXX")
66 | export AUTOENV_AUTH_FILE="${TMPDIR}/autoenv_authorized" # Don't use default auth file
67 | export TMPDIR
68 | cd "${TMPDIR}"
69 | # Run this test
70 | eval "$(echo "$shell" | cut -d':' -f2) ${basedir}/$current_test.sh" > "${basedir}/lasttest.log" 2>&1
71 | # Tear this test down
72 | echo "Success."
73 | cd "${oldpwd}"
74 | rm -rf "${TMPDIR}"
75 | done
76 | done
77 | unset -v IFS
78 |
79 | trap '' EXIT INT TERM
80 |
--------------------------------------------------------------------------------
/tests/test_auth_spaces.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | AUTOENV_AUTH_FILE="${AUTOENV_AUTH_FILE} with spaces"
4 |
5 | . "${FUNCTIONS}"
6 | . "${ACTIVATE_SH}"
7 |
8 | # Prepare files/directories
9 | mkdir -pv 'a/b' 'c/d'
10 | echo 'echo a' > "a/.env"
11 | echo 'echo b' > "a/b/.env"
12 | echo 'echo c' > "c/.env"
13 |
14 | # Test simple cd
15 | patterntest 'echo "Y" | cd a' '.*a$'
16 | # Test cd to subdirectory
17 | patterntest 'echo "Y" | cd a/b' '.*a
18 | b$'
19 | # Test cd with env in parent directory
20 | patterntest 'echo "Y" | cd c/d' '.*c$'
21 | # Check cd into nonexistent directory
22 | echo "Y" | cd d && exit 1 || :
23 |
--------------------------------------------------------------------------------
/tests/test_cd_env.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a/.env' 'b/.env'
8 | echo 'echo b' > 'b/.env/.env'
9 |
10 | # Test without a .env file
11 | patterntest 'echo "Y" | cd a/.env' '^$'
12 | # Test with a directory with .env file
13 | patterntest 'echo "Y" | cd b/.env' '.*b$'
14 |
--------------------------------------------------------------------------------
/tests/test_cd_env_leave.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a/b' 'a/bz'
8 | echo 'echo zulu' > 'a/b/.env.leave'
9 |
10 | AUTOENV_ENABLE_LEAVE=1
11 | cd 'a/b'
12 | patterntest 'echo "Y" | cd ../../a/bz' 'zulu$'
13 |
--------------------------------------------------------------------------------
/tests/test_cd_spaces.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a a/b b' 'c c/d d'
8 | echo 'echo a' > 'a a/.env'
9 | echo 'echo b' > 'a a/b b/.env'
10 | echo 'echo c' > 'c c/.env'
11 |
12 | # Test simple cd
13 | patterntest 'echo "Y" | cd "a a"' '.*a$'
14 | # Test cd to subdirectory
15 | patterntest 'echo "Y" | cd "a a/b b"' '.*a
16 | b$'
17 | # Test cd with env in parent directory
18 | patterntest 'echo "Y" | cd "c c/d d"' '.*c$'
19 | # Test cd into nonexistent directory
20 | echo "Y" | cd 'd d' && exit 1 || :
21 |
--------------------------------------------------------------------------------
/tests/test_colons.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a:a/b:b' 'c:c/d:d'
8 | echo 'echo a' > "a:a/.env"
9 | echo 'echo b' > "a:a/b:b/.env"
10 | echo 'echo c' > "c:c/.env"
11 |
12 | # Test simple cd
13 | patterntest 'echo "Y" | cd a:a' '.*a$'
14 | # Test cd to subdirectory
15 | patterntest 'echo "Y" | cd a:a/b:b' '.*a
16 | b$'
17 | # Test cd with env in parent directory
18 | patterntest 'echo "Y" | cd c:c/d:d' '.*c$'
19 | # Check cd into nonexistent directory
20 | echo "Y" | cd 'd:d' && exit 1 || :
21 |
--------------------------------------------------------------------------------
/tests/test_custom_filename.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 |
5 | AUTOENV_ENV_FILENAME='.autoenv'
6 | export AUTOENV_ENV_FILENAME
7 | . "${ACTIVATE_SH}"
8 |
9 | # Prepare files/directories
10 | mkdir -pv 'a/b' 'c/d'
11 | echo 'echo a' > "a/.autoenv"
12 | echo 'echo b' > "a/b/.autoenv"
13 | echo 'echo c' > "c/.autoenv"
14 |
15 | # Test simple cd
16 | patterntest 'echo "Y" | cd a' '.*a$'
17 | # Test cd to subdirectory
18 | ( echo "Y" | cd a/b )
19 | patterntest 'echo "Y" | cd a/b' '.*a
20 | b$'
21 | # Test cd with env in parent directory
22 | patterntest 'echo "Y" | cd c/d' '.*c$'
23 | # Check cd into nonexistent directory
24 | echo "Y" | cd d && exit 1 || :
25 |
--------------------------------------------------------------------------------
/tests/test_default.bats:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | load './util/init.sh'
4 |
5 | @test "Declares function 'enable_autoenv'" {
6 | source "$BATS_TEST_DIRNAME/../activate.sh"
7 |
8 | [ "$(type -t enable_autoenv)" = 'function' ]
9 | }
10 |
11 |
12 | @test "Works by default" {
13 | mkdir -p './dir'
14 | printf '%s\n' 'echo abc' > './dir/.env'
15 |
16 | run bash -c "
17 | source '$BATS_TEST_DIRNAME/../activate.sh'
18 | cd './dir'
19 | "
20 |
21 | assert_success
22 | assert_line 'abc'
23 | }
24 |
25 | @test "Fails by default" {
26 | mkdir -p './dir'
27 |
28 | run bash -c "
29 | source '$BATS_TEST_DIRNAME/../activate.sh'
30 | cd './dir'
31 | "
32 |
33 | assert_success
34 | assert_output ''
35 | }
36 |
37 | @test "Works with 'AUTOENV_ENV_FILENAME'" {
38 | mkdir -p './dir'
39 | printf '%s\n' 'echo special_filename' > './dir/coolenv'
40 |
41 | run bash -c "
42 | AUTOENV_ENV_FILENAME='coolenv'
43 | source '$BATS_TEST_DIRNAME/../activate.sh'
44 | cd './dir'
45 | "
46 |
47 | assert_success
48 | assert_line 'special_filename'
49 | }
50 |
51 |
52 |
--------------------------------------------------------------------------------
/tests/test_doubleslash.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a/b' 'c/d'
8 | echo 'echo a' > "a/.env"
9 | echo 'echo b' > "a/b/.env"
10 | echo 'echo c' > "c/.env"
11 |
12 | # Test simple cd
13 | patterntest 'echo "Y" | cd a/' '.*a$'
14 | # Test absolute cd
15 | patterntest "echo "Y" | cd /${PWD}/a/" '.*a$'
16 | # Test cd to subdirectory
17 | ( echo "Y" | cd a/b )
18 | patterntest 'echo "Y" | cd a//b/' '.*a
19 | b$'
20 | # Test cd with env in parent directory
21 | patterntest 'echo "Y" | cd c//d/' '.*c$'
22 | # Check cd into nonexistent directory
23 | echo "Y" | cd d// && exit 1 || :
24 |
--------------------------------------------------------------------------------
/tests/test_noclobber.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | mkdir a
7 | echo 'echo a' > a/.env
8 |
9 | patterntest 'set -C; echo "Y" | cd a' '.*a$'
10 |
11 |
--------------------------------------------------------------------------------
/tests/test_not_file.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | #####
7 | # Tests what happens when .env is not a file.
8 | #####
9 |
10 | # Prepare files/directories
11 | mkdir -pv 'a/.env' 'b'
12 | mkfifo 'b/.env'
13 |
14 | # .env is a directory
15 | patterntest 'echo "Y" | cd a' '^$'
16 | # .env is a fifo
17 | patterntest 'echo "Y" | cd b' '^$'
18 |
--------------------------------------------------------------------------------
/tests/test_paths.bats:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | load './util/init.sh'
4 |
5 | @test "Works with regular path" {
6 | mkdir -p './dir'
7 | printf '%s\n' 'echo a' > './dir/.env'
8 |
9 | run bash -c "
10 | source '$BATS_TEST_DIRNAME/../activate.sh'
11 | cd './dir'
12 | $1
13 | "
14 |
15 | assert_success
16 | assert_line 'a'
17 | }
18 |
--------------------------------------------------------------------------------
/tests/test_prompt.bats:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | load './util/init.sh'
4 |
5 | setup() {
6 | export AUTOENV_AUTH_FILE="$BATS_FILE_TMPDIR/auth.txt"
7 |
8 | cd "$BATS_TEST_TMPDIR"
9 | }
10 |
11 | @test "Entering 'y' no longer prompts" {
12 | mkdir -p './dir'
13 | printf '%s\n' 'echo 123' > './dir/.env'
14 |
15 | run bash -c "
16 | source '$BATS_TEST_DIRNAME/../activate.sh'
17 | cd './dir' <<< 'y'
18 | "
19 |
20 | assert_success
21 | assert_line -p 'New or modified env file detected'
22 | assert_line -p 'echo 123'
23 |
24 | run bash -c "
25 | source '$BATS_TEST_DIRNAME/../activate.sh'
26 | cd './dir'
27 | "
28 |
29 | assert_success
30 | refute_line -p 'New or modified env file detected'
31 | refute_line -p 'echo 123'
32 | assert_line '123'
33 | }
34 |
35 | @test "Entering 'n' prompts again" {
36 | mkdir -p './dir'
37 | printf '%s\n' 'echo 123' > './dir/.env'
38 |
39 | run bash -c "
40 | source '$BATS_TEST_DIRNAME/../activate.sh'
41 | cd './dir' <<< 'n'
42 | "
43 | assert_success
44 | assert_line -p 'New or modified env file detected'
45 | assert_line -p 'echo 123'
46 |
47 | run bash -c "
48 | source '$BATS_TEST_DIRNAME/../activate.sh'
49 | cd './dir' <<< 'n'
50 | "
51 | assert_success
52 | assert_line -p 'New or modified env file detected'
53 | assert_line -p 'echo 123'
54 | }
55 |
56 | @test "Entering 'd' does not prompt again" {
57 | mkdir -p './dir'
58 | printf '%s\n' 'echo 123' > './dir/.env'
59 |
60 | run bash -c "
61 | source '$BATS_TEST_DIRNAME/../activate.sh'
62 | cd './dir' <<< 'd'
63 | "
64 | assert_success
65 | assert_line -p 'New or modified env file detected'
66 | assert_line -p 'echo 123'
67 |
68 | run bash -c "
69 | source '$BATS_TEST_DIRNAME/../activate.sh'
70 | cd './dir' <<< 'y'
71 | "
72 | assert_success
73 | assert_output ''
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/tests/test_simple.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # Prepare files/directories
7 | mkdir -pv 'a/b' 'c/d'
8 | echo 'echo a' > "a/.env"
9 | echo 'echo b' > "a/b/.env"
10 | echo 'echo c' > "c/.env"
11 |
12 | # Test simple cd
13 | patterntest 'echo "Y" | cd a' '.*a$'
14 | # Test cd to subdirectory
15 | ( echo "Y" | cd a/b )
16 | patterntest 'echo "Y" | cd a/b' '.*a
17 | b$'
18 | # Test cd with env in parent directory
19 | patterntest 'echo "Y" | cd c/d' '.*c$'
20 | # Check cd into nonexistent directory
21 | echo "Y" | cd d && exit 1 || :
22 |
--------------------------------------------------------------------------------
/tests/test_symlink.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=sh
2 |
3 | . "${FUNCTIONS}"
4 | . "${ACTIVATE_SH}"
5 |
6 | # .env might be a symlink
7 | # .env might be a symlink to a parent directory
8 | # .env might be a symlink to a child directory
9 | # .env might be a symlink to a nonexistent file
10 | # The current directory might be a symlink
11 |
12 | # Structure:
13 | # a
14 | # - b
15 | # - .env
16 | # - c
17 | # - .env -> ../b/.env
18 | # - d
19 | # - .env -> ../nonexistent
20 | # - e -> c
21 | # b
22 | # - c
23 | # - .env -> ../.env
24 | # - .env
25 | # c
26 | # - d
27 | # - .env
28 | # - .env -> e/.env
29 |
30 |
31 | # Prepare files/directories
32 | mkdir -pv 'a/b' 'a/c' 'a/d'
33 | mkdir -pv 'b/c'
34 | mkdir -pv 'c/d'
35 | ln -s '../b/.env' 'a/c/.env'
36 | ln -s '../nonexistent' 'a/d/.env'
37 | ln -s '../.env' 'b/c/.env'
38 | ln -s 'd/.env' 'c/.env'
39 | ln -s 'c' 'a/e'
40 | echo 'echo b' > 'a/b/.env'
41 | echo 'echo b' > 'b/.env'
42 | echo 'echo d' > 'c/d/.env'
43 |
44 | # .env is a smylink
45 | patterntest 'echo "Y" | cd a/c' '.*b$'
46 | # .env is a symlink to a parent directory
47 | patterntest 'yes "Y" | cd b/c' '.*b$'
48 | # .env is a symlink to a child directory
49 | patterntest 'yes "Y" | cd c' '.*d$'
50 | # .env is a nonexistent symlink
51 | patterntest 'echo "Y" | cd a/d' '^$'
52 | # The current directory is a symlink
53 | patterntest 'echo "Y" | cd a/e' '.*b$'
54 |
--------------------------------------------------------------------------------
/tests/test_variables.bats:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | load './util/init.sh'
4 |
5 | @test "Variable AUTOENV_CUR_FILE is exported and correct" {
6 | source "$BATS_TEST_DIRNAME/../activate.sh"
7 | cat > .env <<"EOF"
8 | printf '%s\n' "file: $AUTOENV_CUR_FILE"
9 | if export -p | grep -q AUTOENV_CUR_FILE; then
10 | printf '%s\n' "AUTOENV_CUR_FILE exported"
11 | fi
12 | if [[ -o allexport ]]; then
13 | printf '%s\n' "option: allexport set"
14 | fi
15 | EOF
16 | local expected_cur_file="$PWD/.env"
17 |
18 | run cd .
19 | [ "$output" = "file: $expected_cur_file
20 | AUTOENV_CUR_FILE exported
21 | option: allexport set" ]
22 | }
23 |
24 | @test "Variable AUTOENV_CUR_DIR is exported and correct" {
25 | source "$BATS_TEST_DIRNAME/../activate.sh"
26 | cat > .env <<"EOF"
27 | printf '%s\n' "file: $AUTOENV_CUR_DIR"
28 | if export -p | grep -q AUTOENV_CUR_DIR; then
29 | printf '%s\n' "AUTOENV_CUR_DIR exported"
30 | fi
31 | if [[ -o allexport ]]; then
32 | printf '%s\n' "option: allexport set"
33 | fi
34 | EOF
35 | local expected_cur_file="$PWD"
36 |
37 | run cd .
38 | [ "$output" = "file: $expected_cur_file
39 | AUTOENV_CUR_DIR exported
40 | option: allexport set" ]
41 | }
42 |
--------------------------------------------------------------------------------
/tests/util/init.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | source './tests/util/test_util.sh'
4 | source './node_modules/@hyperupcall/bats-all/load.bash'
5 |
6 | setup() {
7 | unset -v BASH_ENV
8 | export AUTOENV_AUTH_FILE="$BATS_FILE_TMPDIR/auth.txt"
9 | export AUTOENV_ASSUME_YES='yes'
10 |
11 | cd "$BATS_TEST_TMPDIR"
12 | }
13 |
14 | teardown() {
15 | cd "$BATS_SUITE_TMPDIR"
16 | }
17 |
--------------------------------------------------------------------------------
/tests/util/test_util.sh:
--------------------------------------------------------------------------------
1 | # shellcheck shell=bash
2 |
3 | test_util.init_env() {
4 | mkdir -p './dir'
5 | printf '%s\n' "$1" > './dir/.env'
6 | }
7 |
8 | test_util.activate_env() {
9 | run bash -c "
10 | source '${BATS_TEST_DIRNAME}/../activate.sh'
11 | cd './dir'
12 | $1
13 | "
14 | }
15 |
--------------------------------------------------------------------------------