Skip to content

Commit cf83f5f

Browse files
committed
✨ Add enhanced direnvrc with virtualenv helpers
1 parent 0bb9687 commit cf83f5f

File tree

1 file changed

+248
-1
lines changed

1 file changed

+248
-1
lines changed

home/.direnvrc

Lines changed: 248 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,252 @@
1+
# ----------------------------------------------------------------
2+
# Enhanced direnvrc - replaces virtualenvwrapper functionality
3+
# ----------------------------------------------------------------
4+
5+
# Set PROJECT_HOME if not already set
6+
export PROJECT_HOME="${PROJECT_HOME:-${HOME}/Projects}"
7+
8+
# Ensure PROJECT_HOME directory exists
9+
if [[ ! -d "${PROJECT_HOME}" ]]; then
10+
mkdir -p "${PROJECT_HOME}"
11+
fi
12+
13+
# Auto-detect and activate virtualenv based on project structure
14+
auto_virtualenv() {
15+
# Check for common Python project indicators
16+
if [[ -f "pyproject.toml" || -f "requirements.txt" || -f "setup.py" || -f "Pipfile" ]]; then
17+
local project_name="$(basename "$(pwd)")"
18+
local venv_candidates=(
19+
"venv"
20+
".venv"
21+
"env"
22+
".env"
23+
"${HOME}/.virtualenvs/${project_name}"
24+
)
25+
26+
for venv_dir in "${venv_candidates[@]}"; do
27+
if [[ -d "$venv_dir" && -f "$venv_dir/bin/activate" ]]; then
28+
layout_python_venv python3 "$venv_dir"
29+
return 0
30+
fi
31+
done
32+
33+
# If no venv found but we have project indicators, offer to create one
34+
if command -v uvx >/dev/null 2>&1; then
35+
uvx --quiet rich --print "[yellow]Python project detected but no virtual environment found[/yellow]"
36+
uvx --quiet rich --print "[blue]Consider running[/blue]: layout_python_venv python3 venv"
37+
fi
38+
fi
39+
}
40+
41+
# Enhanced layout_python with project detection
42+
layout_python() {
43+
local python_exe="${1:-python3}"
44+
local venv_dir="${2:-venv}"
45+
46+
# If we're in a project directory under PROJECT_HOME, use project-specific venv
47+
local current_project=""
48+
if [[ "$(pwd)" == "${PROJECT_HOME}"/* ]]; then
49+
current_project="$(basename "$(pwd)")"
50+
venv_dir="${HOME}/.virtualenvs/${current_project}"
51+
fi
52+
53+
layout_python_venv "$python_exe" "$venv_dir"
54+
}
55+
56+
# Create and activate a Python virtual environment
57+
layout_python_venv() {
58+
local python_exe="${1:-python3}"
59+
local venv_dir="${2:-venv}"
60+
61+
# Create venv if it doesn't exist
62+
if [[ ! -d "$venv_dir" ]]; then
63+
log_status "Creating virtual environment: $venv_dir"
64+
"$python_exe" -m venv "$venv_dir"
65+
66+
# Upgrade pip and install uv (matches your postmkvirtualenv hook)
67+
"$venv_dir/bin/python" -m pip install --upgrade pip uv
68+
69+
# Rich output (matches your virtualenvwrapper style)
70+
if command -v uvx >/dev/null 2>&1; then
71+
uvx --quiet rich --print "[green]Virtual environment created[/green]: $venv_dir"
72+
fi
73+
fi
74+
75+
# Activate the virtual environment
76+
source "$venv_dir/bin/activate"
77+
export VIRTUAL_ENV="$(pwd)/$venv_dir"
78+
PATH_add "$venv_dir/bin"
79+
80+
# Set environment variables (matches your postactivate hook)
81+
export VIRTUAL_ENV_NAME="$(basename "$VIRTUAL_ENV")"
82+
83+
# Rich output for activation
84+
if command -v uvx >/dev/null 2>&1; then
85+
uvx --quiet rich --print "[green]Virtual environment activated[/green]: $VIRTUAL_ENV_NAME"
86+
fi
87+
}
88+
89+
# List all virtual environments (replaces lsvirtualenv)
90+
lsvirtualenv() {
91+
local venvs_dir="${HOME}/.virtualenvs"
92+
93+
if [[ ! -d "$venvs_dir" ]]; then
94+
echo "No virtual environments found"
95+
return 0
96+
fi
97+
98+
echo "Available virtual environments:"
99+
for venv in "$venvs_dir"/*; do
100+
if [[ -d "$venv" && -f "$venv/bin/python" ]]; then
101+
local venv_name="$(basename "$venv")"
102+
local python_version="$("$venv/bin/python" --version 2>/dev/null)"
103+
echo " $venv_name ($python_version)"
104+
fi
105+
done
106+
}
107+
108+
# Create a new project with virtualenv (replaces mkproject)
109+
mkproject() {
110+
local project_name="$1"
111+
local python_version="${2:-3.11}"
112+
113+
if [[ -z "$project_name" ]]; then
114+
echo "Usage: mkproject <project_name> [python_version]"
115+
return 1
116+
fi
117+
118+
local project_dir="${PROJECT_HOME}/${project_name}"
119+
local venv_dir="${HOME}/.virtualenvs/${project_name}"
120+
121+
# Rich output for pre-creation
122+
if command -v uvx >/dev/null 2>&1; then
123+
uvx --quiet rich --print "[yellow]Creating project[/yellow]: $project_name"
124+
uvx --quiet rich --print "[blue]PROJECT_HOME[/blue]: ${PROJECT_HOME}"
125+
fi
126+
127+
# Create project directory
128+
mkdir -p "$project_dir"
129+
130+
# Create virtual environment
131+
if command -v pyenv >/dev/null 2>&1; then
132+
pyenv virtualenv "$python_version" "$project_name"
133+
else
134+
python3 -m venv "$venv_dir"
135+
"$venv_dir/bin/python" -m pip install --upgrade pip uv
136+
fi
137+
138+
# Rich output for post-creation
139+
if command -v uvx >/dev/null 2>&1; then
140+
uvx --quiet rich --print "[green]Project created[/green]: $project_dir"
141+
uvx --quiet rich --print "[green]Virtual environment created[/green]: $project_name"
142+
fi
143+
144+
# Change to project directory
145+
cd "$project_dir"
146+
}
147+
148+
# Remove a project and its virtualenv (replaces rmproject)
149+
rmproject() {
150+
local project_name="$1"
151+
152+
if [[ -z "$project_name" ]]; then
153+
echo "Usage: rmproject <project_name>"
154+
return 1
155+
fi
156+
157+
local project_dir="${PROJECT_HOME}/${project_name}"
158+
local venv_dir="${HOME}/.virtualenvs/${project_name}"
159+
160+
# Rich output for pre-removal
161+
if command -v uvx >/dev/null 2>&1; then
162+
uvx --quiet rich --print "[yellow]Removing project[/yellow]: $project_name"
163+
fi
164+
165+
# Remove project directory
166+
if [[ -d "$project_dir" ]]; then
167+
rm -rf "$project_dir"
168+
fi
169+
170+
# Remove virtual environment
171+
if [[ -d "$venv_dir" ]]; then
172+
rm -rf "$venv_dir"
173+
elif command -v pyenv >/dev/null 2>&1; then
174+
pyenv virtualenv-delete -f "$project_name"
175+
fi
176+
177+
# Rich output for post-removal
178+
if command -v uvx >/dev/null 2>&1; then
179+
uvx --quiet rich --print "[green]Project removed[/green]: $project_name"
180+
fi
181+
}
182+
183+
# Scan virtualenvs and display their python versions (from your virtualenv.justfile)
184+
scan_virtualenvs() {
185+
python3 -c "
186+
import subprocess
187+
from pathlib import Path
188+
189+
folders = [folder for folder in Path(Path.home(), '.virtualenvs').glob('*/bin/python')]
190+
for command in folders:
191+
try:
192+
output = subprocess.run(f'{command} --version'.split(), capture_output=True, text=True)
193+
venv_name = command.parent.parent.name
194+
version = output.stdout.strip() or output.stderr.strip()
195+
print(f'{venv_name}: {version}')
196+
except FileNotFoundError:
197+
pass
198+
"
199+
}
200+
201+
# Upgrade pip in all virtualenvs (from your virtualenv.justfile)
202+
upgrade_all_virtualenvs() {
203+
for venv_dir in "${HOME}/.virtualenvs"/*/; do
204+
if [[ -f "${venv_dir}bin/python" ]]; then
205+
echo "Upgrading: $(basename "$venv_dir")"
206+
"${venv_dir}bin/python" --version
207+
"${venv_dir}bin/python" -m pip --version
208+
"${venv_dir}bin/python" -m pip install --upgrade pip uv
209+
echo
210+
fi
211+
done
212+
}
213+
214+
# Enhanced use_python function with virtualenv management
1215
use_python() {
2-
local python_root=$HOME/.pyenv/versions/$1
216+
local python_version="$1"
217+
local python_root="$HOME/.pyenv/versions/$python_version"
218+
219+
if [[ ! -d "$python_root" ]]; then
220+
log_error "Python version $python_version not found in pyenv"
221+
return 1
222+
fi
223+
3224
load_prefix "$python_root"
4225
layout_python "$python_root/bin/python"
5226
}
227+
228+
# Use a specific virtualenv by name (replaces workon)
229+
use_virtualenv() {
230+
local venv_name="$1"
231+
local venv_dir="${HOME}/.virtualenvs/${venv_name}"
232+
233+
if [[ ! -d "$venv_dir" ]]; then
234+
log_error "Virtual environment '$venv_name' not found"
235+
return 1
236+
fi
237+
238+
export VIRTUAL_ENV="$venv_dir"
239+
export VIRTUAL_ENV_NAME="$venv_name"
240+
PATH_add "$venv_dir/bin"
241+
242+
# Rich output for activation
243+
if command -v uvx >/dev/null 2>&1; then
244+
uvx --quiet rich --print "[green]Virtual environment activated[/green]: $venv_name"
245+
fi
246+
}
247+
248+
# Hook into direnv's directory change detection
249+
# This replaces the need for manual workon/deactivate
250+
if [[ -n "$DIRENV_DIR" ]]; then
251+
auto_virtualenv
252+
fi

0 commit comments

Comments
 (0)