Private/Common/Eigenverft.Manifested.Sandbox.Shared.Pip.ps1

<#
    Eigenverft.Manifested.Sandbox.Shared.Pip
#>


function Get-ManagedPythonPipConfigPath {
<#
.SYNOPSIS
Returns the managed pip configuration file path for a Python home.
 
.DESCRIPTION
Builds the runtime-local `pip.ini` path that the sandbox-managed Python
wrappers and pip helpers use for persisted pip settings.
 
.PARAMETER PythonHome
The root directory that contains the managed Python executable.
 
.EXAMPLE
Get-ManagedPythonPipConfigPath -PythonHome 'C:\Sandbox\tools\python\3.13.12\amd64'
 
.NOTES
This helper only composes the path and does not create the file.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonHome
    )

    return (Join-Path $PythonHome 'pip.ini')
}

function Get-ManagedPythonPipCacheRoot {
<#
.SYNOPSIS
Returns the managed pip cache directory.
 
.DESCRIPTION
Resolves the sandbox-owned pip cache root beneath the manifested Python cache
layout for the supplied or default local root.
 
.PARAMETER LocalRoot
The sandbox local root used to calculate the managed cache layout.
 
.EXAMPLE
Get-ManagedPythonPipCacheRoot
 
.NOTES
The returned path is used for `PIP_CACHE_DIR` in managed runtimes.
#>

    [CmdletBinding()]
    param(
        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $layout = Get-ManifestedLayout -LocalRoot $LocalRoot
    return (Join-Path $layout.PythonCacheRoot 'pip')
}

function Test-ManifestedManagedPythonCommand {
<#
.SYNOPSIS
Determines whether a Python executable belongs to the managed sandbox layout.
 
.DESCRIPTION
Checks whether the supplied Python executable path resolves underneath the
manifested Python tools root for the selected sandbox local root.
 
.PARAMETER PythonExe
The Python executable path to evaluate.
 
.PARAMETER LocalRoot
The sandbox local root used to resolve the managed tools directory.
 
.EXAMPLE
Test-ManifestedManagedPythonCommand -PythonExe 'C:\Sandbox\tools\python\3.13.12\amd64\python.exe'
 
.NOTES
This guard is used to avoid applying managed pip settings to external runtimes.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $layout = Get-ManifestedLayout -LocalRoot $LocalRoot
    return (Test-ManifestedPathIsUnderRoot -Path $PythonExe -RootPath $layout.PythonToolsRoot)
}

function Get-ManifestedPythonPipConfiguration {
<#
.SYNOPSIS
Builds the effective pip configuration context for a Python command.
 
.DESCRIPTION
Determines whether the supplied Python executable belongs to a sandbox-managed
runtime and, when it does, resolves the runtime-local `pip.ini`,
`PIP_CONFIG_FILE`, and `PIP_CACHE_DIR` values that should be applied before
running pip-related commands.
 
.PARAMETER PythonExe
The Python executable path to inspect.
 
.PARAMETER LocalRoot
The pinned sandbox root used to derive managed cache and config locations.
 
.EXAMPLE
Get-ManifestedPythonPipConfiguration -PythonExe 'C:\Sandbox\tools\python\3.13.12\amd64\python.exe'
 
.EXAMPLE
Get-ManifestedPythonPipConfiguration -PythonExe 'C:\Python313\python.exe'
 
.NOTES
External Python runtimes return an empty environment-variable map.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $pythonHome = Split-Path -Parent $PythonExe
    $isManagedPython = Test-ManifestedManagedPythonCommand -PythonExe $PythonExe -LocalRoot $LocalRoot
    $pipConfigPath = $null
    $pipCacheRoot = $null
    $environmentVariables = [ordered]@{}

    if ($isManagedPython) {
        $pipConfigPath = Get-ManagedPythonPipConfigPath -PythonHome $pythonHome
        $pipCacheRoot = Get-ManagedPythonPipCacheRoot -LocalRoot $LocalRoot
        $environmentVariables['PIP_CONFIG_FILE'] = $pipConfigPath
        $environmentVariables['PIP_CACHE_DIR'] = $pipCacheRoot
    }

    [pscustomobject]@{
        IsManagedPython     = $isManagedPython
        PythonExe           = $PythonExe
        PythonHome          = $pythonHome
        PipConfigPath       = $pipConfigPath
        PipCacheRoot        = $pipCacheRoot
        EnvironmentVariables = $environmentVariables
    }
}

function Get-ManifestedPipIndexUri {
<#
.SYNOPSIS
Returns the canonical pip package-index URI.
 
.DESCRIPTION
Provides the package-index endpoint used when evaluating direct versus proxied
network routes for pip traffic.
 
.EXAMPLE
Get-ManifestedPipIndexUri
 
.NOTES
The current implementation targets the public PyPI simple index.
#>

    [CmdletBinding()]
    param()

    return [uri]'https://pypi.org/simple/'
}

function Resolve-ManifestedPipProxyRoute {
<#
.SYNOPSIS
Determines whether pip traffic should use a system proxy.
 
.DESCRIPTION
Consults the system web proxy for the requested package index URI and reports
whether the route is direct or proxied, including the effective proxy URI when
one is required.
 
.PARAMETER IndexUri
The package index URI whose network route should be evaluated.
 
.EXAMPLE
Resolve-ManifestedPipProxyRoute -IndexUri (Get-ManifestedPipIndexUri)
 
.NOTES
Proxy discovery failures are treated as direct access to keep the helper safe.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [uri]$IndexUri
    )

    $proxyUri = $null

    try {
        $systemProxy = [System.Net.WebRequest]::GetSystemWebProxy()
        if ($null -ne $systemProxy) {
            $systemProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials

            if (-not $systemProxy.IsBypassed($IndexUri)) {
                $candidateProxyUri = $systemProxy.GetProxy($IndexUri)
                if ($null -ne $candidateProxyUri -and $candidateProxyUri.AbsoluteUri -ne $IndexUri.AbsoluteUri) {
                    $proxyUri = $candidateProxyUri
                }
            }
        }
    }
    catch {
        $proxyUri = $null
    }

    [pscustomobject]@{
        IndexUri      = $IndexUri.AbsoluteUri
        IndexHost     = $IndexUri.Host
        ProxyUri      = if ($proxyUri) { $proxyUri.AbsoluteUri } else { $null }
        ProxyRequired = ($null -ne $proxyUri)
        Route         = if ($proxyUri) { 'Proxy' } else { 'Direct' }
    }
}

function Get-ManifestedPipConfigDocument {
<#
.SYNOPSIS
Reads a pip configuration file into an in-memory document.
 
.DESCRIPTION
Parses a `pip.ini`-style configuration file into nested ordered hashtables,
preserving section and key ordering for later read and write operations.
 
.PARAMETER ConfigPath
The configuration file to parse.
 
.EXAMPLE
Get-ManifestedPipConfigDocument -ConfigPath 'C:\Sandbox\tools\python\3.13.12\amd64\pip.ini'
 
.NOTES
Missing files return an empty ordered hashtable.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ConfigPath
    )

    $document = [ordered]@{}
    if (-not (Test-Path -LiteralPath $ConfigPath)) {
        return $document
    }

    $currentSection = $null
    foreach ($rawLine in @(Get-Content -LiteralPath $ConfigPath -ErrorAction SilentlyContinue)) {
        $line = $rawLine.Trim()
        if ([string]::IsNullOrWhiteSpace($line)) {
            continue
        }
        if ($line.StartsWith(';') -or $line.StartsWith('#')) {
            continue
        }

        $sectionMatch = [regex]::Match($line, '^\[(.+)\]$')
        if ($sectionMatch.Success) {
            $currentSection = $sectionMatch.Groups[1].Value.Trim()
            if (-not $document.Contains($currentSection)) {
                $document[$currentSection] = [ordered]@{}
            }

            continue
        }

        $keyValueMatch = [regex]::Match($line, '^(?<key>[^=]+?)\s*=\s*(?<value>.*)$')
        if ($keyValueMatch.Success -and -not [string]::IsNullOrWhiteSpace($currentSection)) {
            $document[$currentSection][$keyValueMatch.Groups['key'].Value.Trim()] = $keyValueMatch.Groups['value'].Value.Trim()
        }
    }

    return $document
}

function Get-ManifestedPipConfigValue {
<#
.SYNOPSIS
Reads a single value from a pip configuration document.
 
.DESCRIPTION
Loads the pip configuration file and returns the requested key from the named
section when it exists; otherwise returns `$null`.
 
.PARAMETER ConfigPath
The configuration file to inspect.
 
.PARAMETER Section
The section name that should contain the key.
 
.PARAMETER Key
The key to read from the selected section.
 
.EXAMPLE
Get-ManifestedPipConfigValue -ConfigPath $pipIni -Section 'global' -Key 'proxy'
 
.NOTES
This helper does not create missing sections or keys.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ConfigPath,

        [Parameter(Mandatory = $true)]
        [string]$Section,

        [Parameter(Mandatory = $true)]
        [string]$Key
    )

    $document = Get-ManifestedPipConfigDocument -ConfigPath $ConfigPath
    if (-not $document.Contains($Section)) {
        return $null
    }
    if (-not $document[$Section].Contains($Key)) {
        return $null
    }

    return $document[$Section][$Key]
}

function Set-ManifestedPipConfigValue {
<#
.SYNOPSIS
Writes a single value into a pip configuration file.
 
.DESCRIPTION
Ensures the requested section exists, updates the selected key, and rewrites
the runtime-local pip configuration file in a stable ordered format.
 
.PARAMETER ConfigPath
The configuration file to update.
 
.PARAMETER Section
The section that should contain the key.
 
.PARAMETER Key
The key name to write.
 
.PARAMETER Value
The value to assign to the selected key.
 
.EXAMPLE
Set-ManifestedPipConfigValue -ConfigPath $pipIni -Section 'global' -Key 'proxy' -Value 'http://proxy:8080'
 
.NOTES
The file is written with ASCII encoding to match the surrounding module style.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ConfigPath,

        [Parameter(Mandatory = $true)]
        [string]$Section,

        [Parameter(Mandatory = $true)]
        [string]$Key,

        [Parameter(Mandatory = $true)]
        [string]$Value
    )

    $document = Get-ManifestedPipConfigDocument -ConfigPath $ConfigPath
    if (-not $document.Contains($Section)) {
        $document[$Section] = [ordered]@{}
    }

    $document[$Section][$Key] = $Value

    New-ManifestedDirectory -Path (Split-Path -Parent $ConfigPath) | Out-Null

    $lines = New-Object System.Collections.Generic.List[string]
    foreach ($sectionName in @($document.Keys)) {
        $lines.Add('[' + $sectionName + ']') | Out-Null
        foreach ($keyName in @($document[$sectionName].Keys)) {
            $lines.Add($keyName + ' = ' + $document[$sectionName][$keyName]) | Out-Null
        }
        $lines.Add('') | Out-Null
    }

    if ($lines.Count -gt 0 -and $lines[$lines.Count - 1] -eq '') {
        $lines.RemoveAt($lines.Count - 1)
    }

    Set-Content -LiteralPath $ConfigPath -Value $lines -Encoding ASCII
    return $ConfigPath
}

function Get-ManifestedPipProxyConfigurationStatus {
<#
.SYNOPSIS
Summarizes the current pip proxy configuration state for a Python runtime.
 
.DESCRIPTION
Combines the managed-runtime test, effective network route, and any existing
pip proxy setting to describe what action, if any, is needed before running
pip-related commands.
 
.PARAMETER PythonExe
The Python executable whose pip configuration should be evaluated.
 
.PARAMETER LocalRoot
The sandbox local root used to resolve managed layout paths.
 
.EXAMPLE
Get-ManifestedPipProxyConfigurationStatus -PythonExe $pythonExe
 
.NOTES
The returned object is designed to be reusable by
`Sync-ManifestedPipProxyConfiguration`.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $pipConfiguration = Get-ManifestedPythonPipConfiguration -PythonExe $PythonExe -LocalRoot $LocalRoot
    $indexUri = Get-ManifestedPipIndexUri
    $proxyRoute = Resolve-ManifestedPipProxyRoute -IndexUri $indexUri
    $currentProxy = $null

    if (-not [string]::IsNullOrWhiteSpace($pipConfiguration.PipConfigPath)) {
        $currentProxy = Get-ManifestedPipConfigValue -ConfigPath $pipConfiguration.PipConfigPath -Section 'global' -Key 'proxy'
    }

    if (-not $pipConfiguration.IsManagedPython) {
        $action = 'SkippedExternalPip'
    }
    elseif ($proxyRoute.Route -eq 'Direct') {
        $action = 'DirectNoChange'
    }
    elseif ($currentProxy -eq $proxyRoute.ProxyUri) {
        $action = 'ReusedManagedProxy'
    }
    else {
        $action = 'NeedsManagedProxy'
    }

    [pscustomobject]@{
        PythonExe      = $pipConfiguration.PythonExe
        PythonHome     = $pipConfiguration.PythonHome
        IndexUri       = $proxyRoute.IndexUri
        IndexHost      = $proxyRoute.IndexHost
        ProxyUri       = $proxyRoute.ProxyUri
        ProxyRequired  = $proxyRoute.ProxyRequired
        Route          = $proxyRoute.Route
        Action         = $action
        PipConfigPath  = $pipConfiguration.PipConfigPath
        PipCacheRoot   = $pipConfiguration.PipCacheRoot
        CurrentProxy   = $currentProxy
    }
}

function Sync-ManifestedPipProxyConfiguration {
<#
.SYNOPSIS
Synchronizes the managed pip proxy setting with the effective system route.
 
.DESCRIPTION
Examines the current proxy route to the configured Python package index and, for
sandbox-managed Python runtimes, writes a runtime-local `pip.ini` only when a
proxy is actually required and the existing config does not already match.
 
.PARAMETER PythonExe
The Python executable that owns the managed pip configuration.
 
.PARAMETER Status
Optional precomputed proxy-status object from
`Get-ManifestedPipProxyConfigurationStatus`.
 
.PARAMETER LocalRoot
The pinned sandbox root used for managed cache/config resolution.
 
.EXAMPLE
Sync-ManifestedPipProxyConfiguration -PythonExe 'C:\Sandbox\tools\python\3.13.12\amd64\python.exe'
 
.EXAMPLE
$status = Get-ManifestedPipProxyConfigurationStatus -PythonExe $pythonExe
Sync-ManifestedPipProxyConfiguration -PythonExe $pythonExe -Status $status
 
.NOTES
External Python runtimes are left unchanged.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [pscustomobject]$Status,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    if (-not $Status) {
        $Status = Get-ManifestedPipProxyConfigurationStatus -PythonExe $PythonExe -LocalRoot $LocalRoot
    }

    if ($Status.Action -ne 'NeedsManagedProxy') {
        return $Status
    }

    if (-not [string]::IsNullOrWhiteSpace($Status.PipCacheRoot)) {
        New-ManifestedDirectory -Path $Status.PipCacheRoot | Out-Null
    }

    Set-ManifestedPipConfigValue -ConfigPath $Status.PipConfigPath -Section 'global' -Key 'proxy' -Value $Status.ProxyUri | Out-Null

    [pscustomobject]@{
        PythonExe      = $Status.PythonExe
        PythonHome     = $Status.PythonHome
        IndexUri       = $Status.IndexUri
        IndexHost      = $Status.IndexHost
        ProxyUri       = $Status.ProxyUri
        ProxyRequired  = $Status.ProxyRequired
        Route          = $Status.Route
        Action         = 'ConfiguredManagedProxy'
        PipConfigPath  = $Status.PipConfigPath
        PipCacheRoot   = $Status.PipCacheRoot
        CurrentProxy   = $Status.ProxyUri
    }
}

function Set-ManifestedManagedPipWrappers {
<#
.SYNOPSIS
Creates pip wrapper commands for a managed Python runtime.
 
.DESCRIPTION
Writes `pip.cmd` and `pip3.cmd` wrappers that pin the managed `pip.ini` file
and pip cache directory before delegating to `python.exe -m pip`.
 
.PARAMETER PythonHome
The root directory of the managed Python runtime that should receive wrappers.
 
.PARAMETER LocalRoot
The sandbox local root used to resolve the shared pip cache directory.
 
.EXAMPLE
Set-ManifestedManagedPipWrappers -PythonHome 'C:\Sandbox\tools\python\3.13.12\amd64'
 
.NOTES
This helper is intended for managed runtimes only.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonHome,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $pipConfigPath = Get-ManagedPythonPipConfigPath -PythonHome $PythonHome
    $pipCacheRoot = Get-ManagedPythonPipCacheRoot -LocalRoot $LocalRoot
    New-ManifestedDirectory -Path $pipCacheRoot | Out-Null

    $wrapperLines = @(
        '@echo off',
        'setlocal',
        'set "PIP_CONFIG_FILE=%~dp0pip.ini"',
        ('set "PIP_CACHE_DIR={0}"' -f $pipCacheRoot),
        '"%~dp0python.exe" -m pip %*',
        'exit /b %ERRORLEVEL%'
    )

    $wrapperPaths = @(
        (Join-Path $PythonHome 'pip.cmd'),
        (Join-Path $PythonHome 'pip3.cmd')
    )

    foreach ($wrapperPath in $wrapperPaths) {
        Set-Content -LiteralPath $wrapperPath -Value $wrapperLines -Encoding ASCII
    }

    [pscustomobject]@{
        PythonHome    = $PythonHome
        PipConfigPath = $pipConfigPath
        PipCacheRoot  = $pipCacheRoot
        WrapperPaths  = @($wrapperPaths)
    }
}

function Get-ManagedPythonSanitizedEnvironmentVariableNames {
<#
.SYNOPSIS
Returns Python environment variables that should be cleared for managed runtimes.
 
.DESCRIPTION
Lists session-level Python environment variables that can interfere with the
isolated embeddable runtime layout when a sandbox-managed Python executable is
launched from a host shell that already has Python-specific configuration.
 
.EXAMPLE
Get-ManagedPythonSanitizedEnvironmentVariableNames
 
.NOTES
These variables are only cleared for sandbox-managed runtimes.
#>

    [CmdletBinding()]
    param()

    return @(
        'PYTHONHOME',
        'PYTHONPATH'
    )
}

function Invoke-ManifestedPythonCommand {
<#
.SYNOPSIS
Invokes Python with managed sandbox environment adjustments when applicable.
 
.DESCRIPTION
Runs a Python command, temporarily applying the runtime-local pip config and
cache variables for managed runtimes when requested and clearing conflicting
Python host variables such as `PYTHONHOME` and `PYTHONPATH`. The previous
process environment is restored even when the Python process fails to start.
 
.PARAMETER PythonExe
The Python executable to run.
 
.PARAMETER Arguments
The argument vector passed to the Python process.
 
.PARAMETER IncludeManagedPipEnvironment
Adds managed `PIP_CONFIG_FILE` and `PIP_CACHE_DIR` variables when the Python
executable belongs to the sandbox-managed runtime layout.
 
.PARAMETER LocalRoot
The pinned sandbox root used to derive managed pip settings.
 
.EXAMPLE
Invoke-ManifestedPythonCommand -PythonExe $pythonExe -Arguments @('-V')
 
.EXAMPLE
Invoke-ManifestedPythonCommand -PythonExe $pythonExe -Arguments @('-m', 'pip', '--version') -IncludeManagedPipEnvironment
 
.NOTES
External Python runtimes are executed without managed environment sanitization.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [Parameter(Mandatory = $true)]
        [string[]]$Arguments,

        [switch]$IncludeManagedPipEnvironment,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    $configuration = Get-ManifestedPythonPipConfiguration -PythonExe $PythonExe -LocalRoot $LocalRoot
    $environmentVariables = [ordered]@{}
    $previousValues = @{}
    $sanitizedVariables = @()
    $output = @()
    $exitCode = $null
    $exceptionMessage = $null

    if ($configuration.IsManagedPython) {
        foreach ($variableName in @(Get-ManagedPythonSanitizedEnvironmentVariableNames)) {
            $environmentVariables[$variableName] = $null
        }

        $sanitizedVariables = @($environmentVariables.Keys)

        if ($IncludeManagedPipEnvironment) {
            foreach ($variableName in @($configuration.EnvironmentVariables.Keys)) {
                $environmentVariables[$variableName] = $configuration.EnvironmentVariables[$variableName]
            }
        }
    }

    try {
        foreach ($variableName in @($environmentVariables.Keys)) {
            $previousValues[$variableName] = [System.Environment]::GetEnvironmentVariable($variableName, 'Process')
            $targetValue = $environmentVariables[$variableName]
            [System.Environment]::SetEnvironmentVariable($variableName, $targetValue, 'Process')
            if ($null -eq $targetValue) {
                Remove-Item -Path ('Env:' + $variableName) -ErrorAction SilentlyContinue
            }
            else {
                Set-Item -Path ('Env:' + $variableName) -Value $targetValue
            }
        }

        $output = @(& $PythonExe @Arguments 2>&1)
        $exitCode = if ($null -ne $LASTEXITCODE) { [int]$LASTEXITCODE } else { 0 }
    }
    catch {
        $exceptionMessage = $_.Exception.Message
        $output += $_
        if ($null -eq $exitCode -and $null -ne $LASTEXITCODE) {
            $exitCode = [int]$LASTEXITCODE
        }
    }
    finally {
        foreach ($variableName in @($environmentVariables.Keys)) {
            $previousValue = $previousValues[$variableName]
            [System.Environment]::SetEnvironmentVariable($variableName, $previousValue, 'Process')
            if ($null -eq $previousValue) {
                Remove-Item -Path ('Env:' + $variableName) -ErrorAction SilentlyContinue
            }
            else {
                Set-Item -Path ('Env:' + $variableName) -Value $previousValue
            }
        }
    }

    $outputLines = @(
        $output |
            ForEach-Object {
                if ($null -eq $_) {
                    return $null
                }

                $_.ToString().Trim()
            } |
            Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
    )

    [pscustomobject]@{
        Output                    = @($output)
        OutputLines               = @($outputLines)
        OutputText                = ($outputLines -join [Environment]::NewLine)
        ExitCode                  = $exitCode
        ExceptionMessage          = $exceptionMessage
        Succeeded                 = ($null -ne $exitCode -and $exitCode -eq 0 -and [string]::IsNullOrWhiteSpace($exceptionMessage))
        Configuration             = $configuration
        IsManagedPython           = $configuration.IsManagedPython
        AppliedEnvironmentVariables = $environmentVariables
        SanitizedVariables        = @($sanitizedVariables)
    }
}

function Invoke-ManifestedPipAwarePythonCommand {
<#
.SYNOPSIS
Invokes Python with the sandbox-managed pip environment when applicable.
 
.DESCRIPTION
Temporarily applies the runtime-local pip configuration and cache environment
variables for a managed Python runtime, executes the requested Python command,
captures its combined output, and restores the previous process environment
afterward.
 
.PARAMETER PythonExe
The Python executable to run.
 
.PARAMETER Arguments
The argument vector passed to the Python process.
 
.PARAMETER LocalRoot
The pinned sandbox root used to derive managed pip settings.
 
.EXAMPLE
Invoke-ManifestedPipAwarePythonCommand -PythonExe $pythonExe -Arguments @('-m', 'pip', '--version')
 
.EXAMPLE
Invoke-ManifestedPipAwarePythonCommand -PythonExe $pythonExe -Arguments @($getPipScriptPath)
 
.NOTES
This helper is the common execution path for managed pip bootstrap and pip
inspection calls.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PythonExe,

        [Parameter(Mandatory = $true)]
        [string[]]$Arguments,

        [string]$LocalRoot = (Get-ManifestedLocalRoot)
    )

    return (Invoke-ManifestedPythonCommand -PythonExe $PythonExe -Arguments $Arguments -IncludeManagedPipEnvironment -LocalRoot $LocalRoot)
}