Skip to content

Commit

Permalink
Improve virtual-environment creation
Browse files Browse the repository at this point in the history
- use `poetry run true` dummy command to create the virtual-env if it
  doesn't exist (this is necessary for `MISE_POETRY_AUTO_INSTALL` to
  work)
- show ANSI colouring when env is created/populated
- general refactoring
  • Loading branch information
joshbode committed Dec 23, 2024
1 parent c285853 commit 48b1645
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SH_SRCFILES = $(shell git ls-files "bin/*")
SHFMT_BASE_FLAGS = -i 2 -ci
SHFMT_BASE_FLAGS = -i 2 -ci --space-redirects

fmt:
shfmt -w $(SHFMT_BASE_FLAGS) $(SH_SRCFILES)
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,19 @@ Automatically activate the poetry virtualenv when entering the directory with th

```toml
[tools]
poetry = {version='latest', pyproject='pyproject.toml'}
python = '3.11' # must be after poetry so the poetry bin is first in PATH
poetry = { version="latest", pyproject="{{ config_root }}/pyproject.toml" }
python = "3.11" # must be after poetry so the poetry bin is first in PATH
```

You can also set `MISE_POETRY_VENV_AUTO=1` to automatically activate the virtualenv if the
project contains both `pyproject.toml` and `poetry.lock` files.
Note: using the `{{ config_root }}` variable ensures that nested directories
containing `.mise*.toml` files correctly inherit the virtual environment from
the parent directory.

Set `MISE_POETRY_AUTO_INSTALL=1` to automatically run `poetry install` to create the virtualenv.

You can also set `MISE_POETRY_VENV_AUTO=1` to automatically activate the virtualenv only if the
project contains a `poetry.lock`.

## License

Licensed under the
Expand Down
56 changes: 40 additions & 16 deletions bin/exec-env
Original file line number Diff line number Diff line change
@@ -1,36 +1,60 @@
#!/usr/bin/env bash
#! /usr/bin/env bash

set -euo pipefail

pyproject=${MISE_TOOL_OPTS__PYPROJECT-}
if [[ -n ${MISE_PROJECT_ROOT-} && ${pyproject} != /* ]]; then
pyproject="${MISE_PROJECT_ROOT}/${pyproject}"
fi

auto_install=${MISE_POETRY_AUTO_INSTALL:-false}
venv_auto=${MISE_POETRY_VENV_AUTO:-false}

# shellcheck source-path=.
source "$MISE_PLUGIN_PATH/bin/utils.sh"
source "${MISE_PLUGIN_PATH}/bin/utils.sh"

setup_virtualenv() {
# if `uv` is being used, exit early and let the user manage venv activation
if [[ -f "uv.lock" ]]; then
if [[ -z ${pyproject} ]]; then
# tool is installed (maybe globally) but project is not activated
return
elif [[ ! -f ${pyproject} ]]; then
echoerr "Project file not found (${pyproject}). Execute \`poetry init\` to create it."
return 1
fi

set +e
venv="$(poetry_venv)"
poetry_venv_exit_code=$?
set -e
local project_root=${pyproject%/*}

if [[ $poetry_venv_exit_code -eq 1 ]]; then
# if `uv` is being used, exit early and let the user manage venv activation
if [[ -f "${project_root}/uv.lock" ]]; then
return
fi

if [[ ! -d "$venv" ]]; then
if [[ "${MISE_POETRY_AUTO_INSTALL:-}" != "true" ]] && [[ "${MISE_POETRY_AUTO_INSTALL:-}" != "1" ]]; then
# don't activate environment if lock file isn't present
if [[ ${venv_auto} == "true" || ${venv_auto} == "1" ]]; then
if [[ ! -f "${project_root}/poetry.lock" ]]; then
return
fi
poetry_bin install
venv="$(poetry_bin env info --path)"
fi

POETRY_ACTIVE=1
MISE_ADD_PATH="$venv/bin"
export VIRTUAL_ENV="$venv" POETRY_ACTIVE MISE_ADD_PATH
local virtual_env
if ! virtual_env=$(poetry_venv "${project_root}"); then
# run a dummy command to ensure the venv exists (creating it if possible)
poetry_bin "${project_root}" --ansi run true

if ! virtual_env=$(poetry_venv "${project_root}"); then
echoerr "Unable to create/activate virtual environment."
return
fi

if [[ ${auto_install} == "true" || ${auto_install} == "1" ]]; then
echoerr "Executing \`poetry install\` to populate virtual environment."
poetry_bin "${project_root}" --ansi install
fi
fi

export POETRY_ACTIVE=1
export VIRTUAL_ENV=${virtual_env}
export MISE_ADD_PATH="${virtual_env}/bin"
}

setup_virtualenv
4 changes: 2 additions & 2 deletions bin/list-all
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ list_all_versions() {

while [[ -n ${URL} ]]; do
RESULT=$(curl -qsSfL --include "$@" "${URL}")
grep -o "${LINE_RE}" <<<"${RESULT}"
if LINK=$(grep -m1 '^link: ' <<<"${RESULT}") && [[ ${LINK} =~ ${NEXT_LINK} ]]; then
grep -o "${LINE_RE}" <<< "${RESULT}"
if LINK=$(grep -m1 '^link: ' <<< "${RESULT}") && [[ ${LINK} =~ ${NEXT_LINK} ]]; then
URL=${BASH_REMATCH[1]}
else
break
Expand Down
38 changes: 16 additions & 22 deletions bin/utils.sh
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
#!/usr/bin/env bash
#! /usr/bin/env bash

if [ "${MISE_TRACE-}" = "1" ]; then
if [[ ${MISE_TRACE-} == 1 ]]; then
set -x
fi

echoerr() {
echo "$1" >&2
printf 'mise-poetry: %s\n' "$@" >&2
}

poetry_bin() {
"$MISE_INSTALL_PATH/bin/poetry" "$@"
local project_root=$1
shift

"${MISE_INSTALL_PATH}/bin/poetry" -C "${project_root}" --no-interaction "$@"
}

poetry_venv() {
local pyproject
pyproject="$(eval "echo ${MISE_TOOL_OPTS__PYPROJECT-}")"
if [[ "${MISE_POETRY_VENV_AUTO:-}" != "true" ]] && [[ "${MISE_POETRY_VENV_AUTO:-}" != "1" ]]; then
if [ "$pyproject" = "" ]; then
return 1
fi
elif [[ ! -f "poetry.lock" ]] | [[ ! -f "pyproject.toml" ]]; then
return 1
else
pyproject="pyproject.toml"
fi
if [[ $pyproject != /* ]] && [[ -n ${MISE_PROJECT_ROOT-} ]]; then
pyproject="${MISE_PROJECT_ROOT-}/$pyproject"
fi
if [[ ! -f $pyproject ]]; then
echoerr "mise-poetry: No pyproject.toml found. Execute \`poetry init\` to create \`$pyproject\` first."
local project_root=$1
shift

local virtual_env
virtual_env=$(poetry_bin "${project_root}" env info --path 2> /dev/null)

if ! [[ -n ${virtual_env} && -d "${virtual_env}" ]]; then
return 1
fi
poetry_bin -C "${pyproject%/*}" env info --path 2>/dev/null
true

printf '%s' "${virtual_env}"
}

0 comments on commit 48b1645

Please sign in to comment.