From 480baf8da7daae8b958ec2edc265227503ba160b Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Sun, 29 May 2022 01:15:40 +0200 Subject: [PATCH] Automatically define pyenv python aliases --- home/.config/shell/aliases | 27 ++--- home/.config/shell/py-alias | 195 ++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 21 deletions(-) create mode 100755 home/.config/shell/py-alias diff --git a/home/.config/shell/aliases b/home/.config/shell/aliases index 392c711..7b886eb 100755 --- a/home/.config/shell/aliases +++ b/home/.config/shell/aliases @@ -79,27 +79,6 @@ alias zb='z -b' # restrict matches to parent directories alias zi='z -I' # cd with interactive fzf selection alias zbi='z -b -I' # pick parent directory to cd into with fzf -## Make aliases for individual cpython/pypy versions -py_versions="\n2\n3\n3.6\n3.7\n3.8\n3.9\n3.10" -# shellcheck disable=SC2139 -echo "$py_versions" | while read -r version; do - for python in python pypy; do - [ "$python" = "python" ] && prefix="py" || prefix="pypy" - - if command -v "$python$version" >/dev/null; then - if [ "$python" = "python" ]; then - alias "pip$version=$python$version -m pip" - else - alias "ppip$version=$python$version -m pip" - fi - alias "$prefix${version}pip=$python$version -m pip" - alias "$prefix$version=$python$version" - alias "i$prefix$version=$python$version -c 'import IPython;IPython.start_ipython()'" - alias "b$prefix$version=$python$version -c 'from bpython.curtsies import main;import sys;sys.exit(main())'" - fi - done -done - # Fallbacks command -v hd > /dev/null || alias hd='hexdump -C' # Cannonical hex dump; some systems have this symlinked command -v md5sum > /dev/null || alias md5sum='md5' # Fallback from `md5sum` to `md5` @@ -295,6 +274,12 @@ if [ ! "$(uname -s)" = 'Darwin' ]; then fi fi +# Autogenerate python aliases +if [ -f ~/.config/shell/py-alias ]; then + # shellcheck source=/home/itsdrike/.config/shell/py-alias + . "$HOME/.config/shell/py-alias" +fi + # Functions if [ -f ~/.config/shell/functions ]; then # shellcheck source=/home/itsdrike/.config/shell/functions diff --git a/home/.config/shell/py-alias b/home/.config/shell/py-alias new file mode 100755 index 0000000..70f57b0 --- /dev/null +++ b/home/.config/shell/py-alias @@ -0,0 +1,195 @@ +#!/usr/bin/env zsh +# Simple script which automatically defines certain aliases for python, +# which will automatically use certain python version +# Versions are automatically obtained from $PYENV_ROOT/versions directories +# NOTE: This assumes that all folders in this directory are valid python versions +# +# Assume we have these installed pyenv python versions 3.6.5, 3.6.12 and 3.10.1: +# - Set full-version aliases: py3.6.5, py3.6.12 and py3.10.1 +# - Set py3 to 3.10.1 (latest with major version 3) +# - Set py3.6 to 3.6.12 (latest with major version 3 and minor version 6) +# - Set py3.10 to 3.10.1 (latest, and only python with major version 3 and minor version 10) + + +# Define all wanted aliases for a given python version +# $1 - full valid pyenv python version (for example '3.6.12', `3.11-dev`, or `pypy3.6-7.2.0-src`) +# $2 - version used in the alias (for example '3.6', '3', or even '', but also `pypy3.7`, ...) +define_aliases() { + version="$1" + alias_version="$2" + cmd_prefix="PYENV_VERSION=$version" + + alias "py$alias_version=$cmd_prefix python" + alias "ipy$alias_version=$cmd_prefix ipython" + alias "bpy$alias_version=$cmd_prefix bpython" + alias "pydoc$alias_version=$cmd_prefix pydoc" + alias "pytest$alias_version=$cmd_prefix pytest" +} + +# Handle splitting full version into prefix, version number and suffix +# Because of the huge variaty of python implemenations and their different namings, +# this function will only be able to handle the default CPython version names, +# which follow the regex pattern of: '\d+\.\d+\.\d+', the rest will print 'full_version;;' +# In the future, this may also include support for some other naming schemes. +# $1 - full valid pyenv python version (for example '3.6.12', `3.11-dev`, or `pypy3.6-7.2.0-src`) +parse_python_version() { + full_version="$1" + if echo "$full_version" | grep -E "[0-9]+\.[0-9]+\.[0-9]+" >/dev/null; then + echo ";$full_version;" + else + echo ';;' + fi +} + +# Prints version number extracted from alias for given version +# $1 - version used in the alias (for example '3.6', '3', or even '', but also 'pypy3.6', ...) +get_alias_version() { + alias_version="$1" + definition="$(alias "py$alias_version")" + full_version="$(echo "$definition" | cut -d= -f3 | cut -d' ' -f1)" + + version_info="$(parse_python_version "$full_version")" + version="$(echo "$version_info" | cut -d';' -f2)" + echo "$version" +} + +# Compares 2 python versions in major, minor and micro parts +# $1 - version #1 +# $2 - version #2 +# Returns: +# 0 - version #1 is newer +# 1 - version #2 is newer +# 2 - versions are equal +version_compare() { + version_1="$1" + version_2="$2" + # ZSH Only: + version_1=(${(@s:.:)version_1}) + version_2=(${(@s:.:)version_2}) + major_1=$version_1[1] + major_2=$version_2[1] + minor_1=$version_1[2] + minor_2=$version_2[2] + micro_1=$version_1[3] + micro_2=$version_2[3] + # POSIX, but slow: + # major_1="$(echo "$version_1" | cut -d. -f1)" + # major_2="$(echo "$version_2" | cut -d. -f1)" + # minor_1="$(echo "$version_1" | cut -d. -f2)" + # minor_2="$(echo "$version_2" | cut -d. -f2)" + # micro_1="$(echo "$version_1" | cut -d. -f3)" + # micro_2="$(echo "$version_2" | cut -d. -f3)" + + # Compare majors + if [ $major_1 -gt $major_2 ]; then + # version 1's major is bigger, version 1 is newer + return 0 + elif [ $major_1 -lt $major_2 ]; then + # version 1's major is smaller, version 2 is newer + return 1 + fi + + # Majors equal, compare minors + if [ $minor_1 -gt $minor_2 ]; then + # version 1's minor is bigger, version 1 is newer + return 0 + elif [ $minor_1 -lt $minor_2 ]; then + # version 1's major is smaller, version 2 is newer + return 1 + fi + + # Minors equal, compare micros + if [ $micro_1 -gt $micro_2 ]; then + # version 1's micro is bigger, version 1 is newer + return 0 + elif [ $micro_1 -lt $micro_2 ]; then + # version 1's micro is smaller, version 2 is newer + return 1 + fi + + # Micros equal, versions equal + return 2 +} + +# Define new aliases if they don't already exsist, in which case override +# if the current version is newer than the version in the alias +# $1 - full valid pyenv python version (for example '3.6.12', `3.11-dev`, or `pypy3.6-7.2.0-src`) +# $2 - version used in the alias (for example '3.6', '3', or even '', but also `pypy3.7`, ...) +try_define_aliases() { + version="$1" + alias_version="$2" + + # Check if alias already exists + if alias "py$alias_version" >/dev/null; then + # Compare version from the existing alias with current version, + # if current is newer, override the existing alias(es) + defined_version="$(get_alias_version "$alias_version")" + if version_compare "$version" "$defined_version"; then + define_aliases "$version" "$alias_version" + # echo "Overwrote '$alias_version' aliases to point to '$version'" + return 0 + else + return 1 + fi + fi + + # The aliases aren't already defined, it's safe to create them + define_aliases "$version" "$alias_version" + # echo "Made '$alias_version' aliases pointing to '$version'" + return 0 +} + +define_version_aliases() { + prefix="$1" + version="$2" + suffix="$3" + + + # ZSH only: + version_data=(${(@s:.:)version}) + major_version=$version_data[0] + minor_version=$version_data[1] + # POSIX, but slow: + # major_version="$(echo "$version" | cut -d. -f1)" + # minor_version="$(echo "$version" | cut -d. -f2)" + + # Define the major.minor.micro (full) alias + try_define_aliases "$version" "$prefix$version$suffix" + # Define the major.minor alias + try_define_aliases "$version" "$prefix$major_version.$minor_version$suffix" + # Define the major alias + try_define_aliases "$version" "$prefix$major_version$suffix" + # Define top level alias + try_define_aliases "$version" "$prefix$suffix" +} + +for python_dir in "$PYENV_ROOT"/versions/*/ ; do + full_version="$(basename $python_dir)" + + version_info="$(parse_python_version "$full_version")" + if [ $version_info = ';;' ]; then + # Version info wasn't obtained successfully, skip this version + echo "Skipped $full_version" + continue + fi + + # ZSH only: + version_data=(${(@s:;:)version_info}) + prefix=$version_data[0] + version=$version_data[1] + suffix=$version_data[2] + # POSIX, but slow: + # prefix="$(echo "$version_info" | cut -d';' -f1)" + # version="$(echo "$version_info" | cut -d';' -f2)" + # suffix="$(echo "$version_info" | cut -d';' -f3)" + + # startTime=$(date +%N) + define_version_aliases "$prefix" "$version" "$suffix" + # endTime=$(date +%N) + # nanos="$(expr $endTime - $startTime)" + # echo "took $(expr $nanos / 1000000) miliseconds" +done + +if command -v poetry >/dev/null 2>&1; then + alias poetry-pyenv='poetry env use "$(pyenv which python)" && poetry install' +fi