Skip to content

Commit 22c1603

Browse files
AI Assistantclaude
andcommitted
feat(upgrade-all): add UV migration for pip/pipx packages
Implement comprehensive migration system to move user-installed pip packages and pipx tools to UV when UV is detected: - Detection: Count user pip packages and pipx tools when UV is present - Reconciliation scripts: - reconcile_pip_to_uv.sh: Migrate user-installed pip packages to UV tools - reconcile_pipx_to_uv.sh: Migrate pipx tools to UV - Makefile targets: make reconcile-pip-to-uv, make reconcile-pipx-to-uv - Interactive confirmation with detailed migration summary - Smart tool detection: Only migrate CLI tools, skip libraries - Skip pip/pipx upgrades in Stage 2 and Stage 4 when UV manages packages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1b71b71 commit 22c1603

4 files changed

Lines changed: 253 additions & 5 deletions

File tree

Makefile.d/user.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ upgrade-%: scripts-perms ## Upgrade tool (e.g., make upgrade-python)
9797
uninstall-%: scripts-perms ## Uninstall tool (e.g., make uninstall-python)
9898
./scripts/install_$*.sh uninstall
9999

100+
reconcile-pip-to-uv: scripts-perms ## Migrate user pip packages to UV tools
101+
@./scripts/reconcile_pip_to_uv.sh
102+
103+
reconcile-pipx-to-uv: scripts-perms ## Migrate pipx tools to UV
104+
@./scripts/reconcile_pipx_to_uv.sh
105+
100106
reconcile-%: scripts-perms ## Reconcile tool installation (e.g., make reconcile-node)
101107
./scripts/install_$*.sh reconcile
102108

scripts/reconcile_pip_to_uv.sh

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# reconcile_pip_to_uv.sh - Migrate user-installed pip packages to UV
5+
# This script moves Python packages from pip (user-installed) to UV tool management
6+
7+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
. "$DIR/lib/common.sh"
9+
10+
DRY_RUN="${DRY_RUN:-0}"
11+
12+
echo "════════════════════════════════════════════════════════"
13+
echo " Reconcile: pip → UV"
14+
echo "════════════════════════════════════════════════════════"
15+
echo ""
16+
17+
# Check prerequisites
18+
if ! command -v uv >/dev/null 2>&1; then
19+
echo "❌ UV not installed. Install UV first:"
20+
echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
21+
exit 1
22+
fi
23+
24+
if ! command -v python3 >/dev/null 2>&1; then
25+
echo "❌ python3 not found"
26+
exit 1
27+
fi
28+
29+
# Get list of user-installed packages
30+
echo "📋 Scanning user-installed pip packages..."
31+
user_packages=$(python3 -m pip list --user --format=freeze 2>/dev/null | grep -v "^#" || true)
32+
33+
if [ -z "$user_packages" ]; then
34+
echo "✓ No user-installed pip packages found"
35+
exit 0
36+
fi
37+
38+
package_count=$(echo "$user_packages" | wc -l)
39+
echo "Found $package_count user-installed packages:"
40+
echo "$user_packages" | sed 's/^/ - /'
41+
echo ""
42+
43+
if [ "$DRY_RUN" = "1" ]; then
44+
echo "🔍 DRY-RUN MODE: Would migrate these packages"
45+
exit 0
46+
fi
47+
48+
# Ask for confirmation
49+
read -p "Migrate these packages to UV? (y/N): " -n 1 -r
50+
echo
51+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
52+
echo "❌ Migration cancelled"
53+
exit 0
54+
fi
55+
56+
echo ""
57+
echo "🔄 Migrating packages to UV..."
58+
echo ""
59+
60+
# Process each package
61+
migrated=0
62+
failed=0
63+
skipped=0
64+
65+
while IFS= read -r package_spec; do
66+
[ -z "$package_spec" ] && continue
67+
68+
# Extract package name (before ==, >=, etc.)
69+
package_name=$(echo "$package_spec" | sed 's/[=<>].*//')
70+
71+
echo "→ Processing: $package_name"
72+
73+
# Check if it's a tool candidate (has CLI entry point)
74+
# Try to find the package in PATH
75+
if command -v "$package_name" >/dev/null 2>&1; then
76+
echo " Installing as UV tool..."
77+
if uv tool install "$package_name" >/dev/null 2>&1; then
78+
echo " ✓ Installed: $package_name (as UV tool)"
79+
80+
# Uninstall from pip
81+
echo " Removing from pip..."
82+
if python3 -m pip uninstall -y "$package_name" >/dev/null 2>&1; then
83+
echo " ✓ Removed from pip"
84+
migrated=$((migrated + 1))
85+
else
86+
echo " ⚠ Warning: Failed to remove from pip (but UV tool installed)"
87+
migrated=$((migrated + 1))
88+
fi
89+
else
90+
echo " ❌ Failed to install as UV tool"
91+
failed=$((failed + 1))
92+
fi
93+
else
94+
# Not a tool, just a library - keep in pip or skip
95+
echo " ⏭ Skipped: $package_name (library, not a tool)"
96+
skipped=$((skipped + 1))
97+
fi
98+
echo ""
99+
done <<< "$user_packages"
100+
101+
echo "════════════════════════════════════════════════════════"
102+
echo "Migration Summary:"
103+
echo " ✓ Migrated: $migrated packages"
104+
echo " ⏭ Skipped: $skipped packages (libraries)"
105+
echo " ❌ Failed: $failed packages"
106+
echo "════════════════════════════════════════════════════════"
107+
108+
if [ "$skipped" -gt 0 ]; then
109+
echo ""
110+
echo "Note: Library packages (non-CLI tools) were skipped."
111+
echo " These should remain managed by pip or moved to project requirements."
112+
fi
113+
114+
if [ "$migrated" -gt 0 ]; then
115+
echo ""
116+
echo "✓ Migration complete! UV is now managing your Python tools."
117+
echo " Run 'uv tool list' to see installed tools"
118+
fi

scripts/reconcile_pipx_to_uv.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# reconcile_pipx_to_uv.sh - Migrate pipx tools to UV
5+
# This script moves all pipx-installed tools to UV tool management
6+
7+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
. "$DIR/lib/common.sh"
9+
10+
DRY_RUN="${DRY_RUN:-0}"
11+
12+
echo "════════════════════════════════════════════════════════"
13+
echo " Reconcile: pipx → UV"
14+
echo "════════════════════════════════════════════════════════"
15+
echo ""
16+
17+
# Check prerequisites
18+
if ! command -v uv >/dev/null 2>&1; then
19+
echo "❌ UV not installed. Install UV first:"
20+
echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
21+
exit 1
22+
fi
23+
24+
if ! command -v pipx >/dev/null 2>&1; then
25+
echo "✓ pipx not installed, nothing to migrate"
26+
exit 0
27+
fi
28+
29+
# Get list of pipx tools
30+
echo "📋 Scanning pipx tools..."
31+
pipx_tools=$(pipx list --short 2>/dev/null || true)
32+
33+
if [ -z "$pipx_tools" ]; then
34+
echo "✓ No pipx tools found"
35+
exit 0
36+
fi
37+
38+
tool_count=$(echo "$pipx_tools" | wc -l)
39+
echo "Found $tool_count pipx tools:"
40+
echo "$pipx_tools" | sed 's/^/ - /'
41+
echo ""
42+
43+
if [ "$DRY_RUN" = "1" ]; then
44+
echo "🔍 DRY-RUN MODE: Would migrate these tools"
45+
exit 0
46+
fi
47+
48+
# Ask for confirmation
49+
read -p "Migrate all pipx tools to UV? (y/N): " -n 1 -r
50+
echo
51+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
52+
echo "❌ Migration cancelled"
53+
exit 0
54+
fi
55+
56+
echo ""
57+
echo "🔄 Migrating tools to UV..."
58+
echo ""
59+
60+
# Process each tool
61+
migrated=0
62+
failed=0
63+
64+
while IFS= read -r tool_name; do
65+
[ -z "$tool_name" ] && continue
66+
67+
# Extract just the package name (first word)
68+
package_name=$(echo "$tool_name" | awk '{print $1}')
69+
70+
echo "→ Migrating: $package_name"
71+
72+
# Install in UV
73+
echo " Installing with UV..."
74+
if uv tool install "$package_name" >/dev/null 2>&1; then
75+
echo " ✓ Installed in UV"
76+
77+
# Uninstall from pipx
78+
echo " Removing from pipx..."
79+
if pipx uninstall "$package_name" >/dev/null 2>&1; then
80+
echo " ✓ Removed from pipx"
81+
migrated=$((migrated + 1))
82+
else
83+
echo " ⚠ Warning: Failed to remove from pipx (but UV tool installed)"
84+
migrated=$((migrated + 1))
85+
fi
86+
else
87+
echo " ❌ Failed to install in UV"
88+
failed=$((failed + 1))
89+
fi
90+
echo ""
91+
done <<< "$pipx_tools"
92+
93+
echo "════════════════════════════════════════════════════════"
94+
echo "Migration Summary:"
95+
echo " ✓ Migrated: $migrated tools"
96+
echo " ❌ Failed: $failed tools"
97+
echo "════════════════════════════════════════════════════════"
98+
99+
if [ "$migrated" -gt 0 ]; then
100+
echo ""
101+
echo "✓ Migration complete! UV is now managing your Python tools."
102+
echo " Run 'uv tool list' to see installed tools"
103+
echo ""
104+
echo "Optional cleanup:"
105+
echo " - Remove pipx itself: pip3 uninstall pipx"
106+
echo " - Remove pipx directory: rm -rf ~/.local/pipx"
107+
fi

scripts/upgrade_all.sh

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,15 @@ stage_2_managers() {
198198

199199
# Language-specific package managers
200200
if command -v pip3 >/dev/null 2>&1; then
201-
# Skip pip if uv is managing Python packages
201+
# Skip pip if uv is managing Python packages, suggest migration
202202
if command -v uv >/dev/null 2>&1; then
203-
log_skip "pip (uv is managing Python packages)"
203+
# Check if there are user-installed pip packages to migrate
204+
local user_packages=$(python3 -m pip list --user --format=freeze 2>/dev/null | grep -v "^#" | wc -l)
205+
if [ "$user_packages" -gt 0 ]; then
206+
log_reconcile "pip ($user_packages user packages, run: make reconcile-pip-to-uv to migrate)"
207+
else
208+
log_skip "pip (uv is managing Python packages)"
209+
fi
204210
# Check if pip module is actually available
205211
elif ! python3 -m pip --version >/dev/null 2>&1; then
206212
log_skip "pip (python3 has no pip module)"
@@ -240,9 +246,15 @@ stage_2_managers() {
240246
fi
241247

242248
if command -v pipx >/dev/null 2>&1; then
243-
# Skip pipx if uv is managing Python tools
249+
# Skip pipx if uv is managing Python tools, suggest migration
244250
if command -v uv >/dev/null 2>&1; then
245-
log_skip "pipx (uv is managing Python tools)"
251+
# Check if there are pipx tools to migrate
252+
local pipx_tools=$(pipx list --short 2>/dev/null | wc -l)
253+
if [ "$pipx_tools" -gt 0 ]; then
254+
log_reconcile "pipx ($pipx_tools tools installed, run: make reconcile-pipx-to-uv to migrate)"
255+
else
256+
log_skip "pipx (uv is managing Python tools)"
257+
fi
246258
elif [ "$DRY_RUN" = "1" ]; then
247259
log_info "DRY-RUN: pip3 install --upgrade pipx"
248260
else
@@ -564,7 +576,12 @@ stage_4_user_packages() {
564576
if command -v pipx >/dev/null 2>&1; then
565577
# Skip pipx packages if uv is managing Python tools
566578
if command -v uv >/dev/null 2>&1; then
567-
log_skip "pipx packages (uv tools handle this)"
579+
local pipx_tools=$(pipx list --short 2>/dev/null | wc -l)
580+
if [ "$pipx_tools" -gt 0 ]; then
581+
log_reconcile "pipx packages ($pipx_tools tools, run: make reconcile-pipx-to-uv to migrate)"
582+
else
583+
log_skip "pipx packages (uv tools handle this)"
584+
fi
568585
elif [ "$DRY_RUN" = "1" ]; then
569586
log_info "DRY-RUN: pipx upgrade-all"
570587
else

0 commit comments

Comments
 (0)