Skip to content

uv: Persist user data#7653

Open
ghyatzo wants to merge 3 commits intoScoopInstaller:masterfrom
ghyatzo:uv-update
Open

uv: Persist user data#7653
ghyatzo wants to merge 3 commits intoScoopInstaller:masterfrom
ghyatzo:uv-update

Conversation

@ghyatzo
Copy link

@ghyatzo ghyatzo commented Feb 18, 2026

  • Use conventional PR title: <manifest-name[@version]|chore>: <general summary of the pull request>
  • I have read the Contributing Guide

Hey,

This might be a bit opinionated, but I wanted uv to behave like pyenv (when installed through scoop) behaved.
With this change scoops makes uv store its python and tool installation paths within the scoop uv folder.

I currently have been using this manifest for the past year or so without issues regarding uv.

It also automatically sets the python and tool shims folders in the path so that it's automatically available.

If too breaking/opinionated feel free to close, but wanted to give the option if it was ever considered.

Cheers.

Related #6955

@github-actions
Copy link
Contributor

All changes look good.

Wait for review from human collaborators.

uv

  • Lint
  • Description
  • License
  • Hashes
  • Checkver
  • Autoupdate
  • Autoupdate Hash Extraction

Check the full log for details.

@ghyatzo ghyatzo changed the title uv@0.10.4: store uv managed artifacts in suv scoop folder uv@0.10.4: store uv managed artifacts in uv scoop folder Feb 18, 2026
@z-Fng
Copy link
Member

z-Fng commented Mar 8, 2026

Should we also migrate the artifacts originally located in $Env:APPDATA/uv to $persist_dir?

@ghyatzo
Copy link
Author

ghyatzo commented Mar 8, 2026

According to https://docs.astral.sh/uv/reference/storage/#tool-executables

I think this manifests already does that by setting all relevant env variables and then save those same folders under persist key.

or maybe I am missing something?

@z-Fng
Copy link
Member

z-Fng commented Mar 8, 2026

I'm referring to users who have previously installed UV via scoop. Their data resides in $Env:APPDATA/uv. After the update, they will 'lose' this data. Should we migrate the data for them, or will UV migrate it automatically?

Main/bucket/bun.json

Lines 26 to 33 in 82c1841

"# Migrate legacy Bun data if it exists and the new persist directory doesn't exist",
"$legacy_bun = Join-Path -Path $env:USERPROFILE -ChildPath '.bun'",
"if ((Test-Path $legacy_bun) -and -not (Test-Path $persist_dir)) {",
" Write-Host \"Migrating legacy Bun data from '$legacy_bun' to '$persist_dir'.\" -ForegroundColor Yellow",
" Move-Item $legacy_bun $persist_dir -Force",
"} elseif ((Test-Path $legacy_bun) -and (Test-Path $persist_dir)) {",
" Write-Host \"Found both '$legacy_bun' and '$persist_dir'. Skipping auto-migration; please migrate manually if needed.\" -ForegroundColor Yellow",
"}",

@ghyatzo
Copy link
Author

ghyatzo commented Mar 8, 2026

Ah that is a very good point.
I believe that uv will redownload the missing python versions on its own the first time that will be needed again. But I don't think it will "reinstall" all the tools's shims automatically. Will need to double check that.

@z-Fng z-Fng changed the title uv@0.10.4: store uv managed artifacts in uv scoop folder uv: Persist user data Mar 9, 2026
@ghyatzo
Copy link
Author

ghyatzo commented Mar 10, 2026

I did some quick tests and uv seems to just pick up whatever is in the target folder. Copying over the legacy location should be a pretty transparent operation for the user.
I'll adapt the bun excerpt shared above to uv as well in the following days

@ghyatzo
Copy link
Author

ghyatzo commented Mar 14, 2026

ok, first attempt.
It's more complicated than bun since by default uv is spread around and dumps all shims inside ~/.local/bin.
Ok that on windows that is probably not used much but it might still contain stuff not related to uv.

here's the overview:

  • only automigrate if the persistdir is not present already
  • move all python versions to persist dir
  • move all executables in ~/.local/bin that match python.exe or pythonX.Y.exe into the shim folder
  • move all tools to the persist dir and build a list of names
  • move mytool.exe only if there is a folder named mytool in the tools install dir.

this should only move previously handled by uv. here's the code in plain:

# Migrate legacy UV data if it exists and the new persist directory doesn't exist
$legacy_uv = Join-Path -Path $env:APPDATA -ChildPath 'uv'

if ((Test-Path $legacy_uv) -and -not (Test-Path $persist_dir)) {
    Write-Host "Migrating legacy uv data from '$legacy_uv' to '$persist_dir'." -ForegroundColor Yellow

    # --- Legacy locations ---
    $legacy_uv_python_data  = Join-Path -Path $legacy_uv -ChildPath 'python'
    $legacy_uv_python_shims = Join-Path (Join-Path $env:USERPROFILE '.local') 'bin'
    $legacy_uv_tools        = Join-Path -Path $legacy_uv -ChildPath 'tools'
    $legacy_uv_tools_shims  = Join-Path (Join-Path $env:USERPROFILE '.local') 'bin'

    # --- Persist target layout ---
    $persist_python_root     = Join-Path $persist_dir 'python'
    $persist_python_versions = Join-Path $persist_python_root 'versions'
    $persist_python_shims    = Join-Path $persist_python_root 'shims'

    $persist_tools_root      = Join-Path $persist_dir 'tools'
    $persist_tools_versions  = Join-Path $persist_tools_root 'versions'
    $persist_tools_shims     = Join-Path $persist_tools_root 'shims'

    # Create target directories
    $null = New-Item -ItemType Directory -Force -Path @(
        $persist_dir,
        $persist_python_root, $persist_python_versions, $persist_python_shims,
        $persist_tools_root,  $persist_tools_versions,  $persist_tools_shims
    )

    # ---- Move Python "versions" content ----
    if (Test-Path $legacy_uv_python_data) {
        Write-Host "-> Moving Python versions from '$legacy_uv_python_data' to '$persist_python_versions'..." -ForegroundColor Cyan
        Get-ChildItem -Path $legacy_uv_python_data -Force |
            ForEach-Object {
                Move-Item -LiteralPath $_.FullName -Destination $persist_python_versions -Force -ErrorAction Stop
            }
    } else {
        Write-Host "-> No legacy Python versions found at '$legacy_uv_python_data'." -ForegroundColor DarkGray
    }

    # ---- Move Python shims: only python.exe or python<major>.<minor>.exe ----
    if (Test-Path $legacy_uv_python_shims) {
        $pythonShimRegex = '^(python(\d+\.\d+)?)\.exe$'  # matches python.exe and pythonX.Y.exe
        $pythonShims = Get-ChildItem -Path $legacy_uv_python_shims -File -Force |
                       Where-Object { $_.Name -match $pythonShimRegex }

        if ($pythonShims) {
            Write-Host "-> Moving Python shims to '$persist_python_shims': $($pythonShims.Name -join ', ')" -ForegroundColor Cyan
            foreach ($shim in $pythonShims) {
                Move-Item -LiteralPath $shim.FullName -Destination (Join-Path $persist_python_shims $shim.Name) -Force -ErrorAction Stop
            }
        } else {
            Write-Host "-> No valid Python shims found in '$legacy_uv_python_shims'." -ForegroundColor DarkGray
        }
    } else {
        Write-Host "-> Legacy Python shim directory not found at '$legacy_uv_python_shims'." -ForegroundColor DarkGray
    }

    # ---- Move Tools "versions" content ----
    if (Test-Path $legacy_uv_tools) {
        Write-Host "-> Moving Tools versions from '$legacy_uv_tools' to '$persist_tools_versions'..." -ForegroundColor Cyan
        Get-ChildItem -Path $legacy_uv_tools -Force |
            ForEach-Object {
                Move-Item -LiteralPath $_.FullName -Destination $persist_tools_versions -Force -ErrorAction Stop
            }
    } else {
        Write-Host "-> No legacy Tools found at '$legacy_uv_tools'." -ForegroundColor DarkGray
    }

    # ---- Move Tools shims: only those matching folder names under /tools/versions ----
    # Build allowlist from folder names directly under $persist_tools_versions
    $toolNames = @()
    if (Test-Path $persist_tools_versions) {
        $toolNames = Get-ChildItem -Path $persist_tools_versions -Directory -Force |
                     Select-Object -ExpandProperty Name
    }

    if ($toolNames.Count -gt 0 -and (Test-Path $legacy_uv_tools_shims)) {
        # For each tool name, move "<tool>.exe" if present
        $moved = @()
        foreach ($tool in $toolNames) {
            $candidate = Join-Path $legacy_uv_tools_shims ($tool + '.exe')
            if (Test-Path $candidate) {
                Move-Item -LiteralPath $candidate -Destination (Join-Path $persist_tools_shims ($tool + '.exe')) -Force -ErrorAction Stop
                $moved += ($tool + '.exe')
            }
        }

        if ($moved.Count -gt 0) {
            Write-Host "-> Moved tool shims to '$persist_tools_shims': $($moved -join ', ')" -ForegroundColor Cyan
        } else {
            Write-Host "-> No matching tool shims found in '$legacy_uv_tools_shims' for tools: $($toolNames -join ', ')." -ForegroundColor DarkGray
        }
    } else {
        if (-not (Test-Path $legacy_uv_tools_shims)) {
            Write-Host "-> Legacy tools shim directory not found at '$legacy_uv_tools_shims'." -ForegroundColor DarkGray
        } else {
            Write-Host "-> No tool folders found under '$persist_tools_versions'; skipping shim migration." -ForegroundColor DarkGray
        }
    }
} elseif ((Test-Path $legacy_uv) -and (Test-Path $persist_dir)) {
    Write-Host "Found both '$legacy_uv' and '$persist_dir'. Skipping auto-migration; please migrate manually if needed." -ForegroundColor Yellow
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants