CoreePower.Lib.Initialize.DevTools.Python.ps1


function Sort-MatchGroups {
    param(
        [Parameter(Mandatory=$true)]
        [Array]$MatchGroupsArray,

        [Parameter(Mandatory=$true)]
        [Array]$SortingParameter,

        [Parameter(Mandatory=$false)]
        [Array]$TryVersionConvertForSorting = @()
    )

    # If there's only one or no SortingParameter left, perform final sorting and return
    if ($SortingParameter.Count -le 1) {
        $param = $SortingParameter[0]

        if ($TryVersionConvertForSorting -contains $param) {
            return $MatchGroupsArray | Sort-Object -Property {
                # Try to convert to version; if fail, use the original value
                try {
                    [Version]$_.($param)
                }
                catch {
                    $_.($param)
                }
            }
        }
        else {
            return $MatchGroupsArray | Sort-Object -Property $param
        }
    }

    # Perform grouping and sort each group separately
    $param = $SortingParameter[0]
    $groupedArray = $MatchGroupsArray | Group-Object -Property $param

    # Initialize the sorted array
    $sortedArray = @()

    foreach ($group in $groupedArray) {
        # Recursively sort each group using the rest of the SortingParameters
        $sortedGroup = Sort-MatchGroups -MatchGroupsArray $group.Group -SortingParameter $SortingParameter[1..($SortingParameter.Count - 1)] -TryVersionConvertForSorting $TryVersionConvertForSorting

        # Append the sorted group to the sorted array
        $sortedArray += $sortedGroup
    }

    return $sortedArray
}

function Sort-MatchGroups2 {
    param(
        [Parameter(Mandatory=$true)]
        [Array]$MatchGroupsArray,

        [Parameter(Mandatory=$true)]
        [Array]$SortingParameter,

        [Parameter(Mandatory=$false)]
        [Array]$TryVersionConvertForSorting = @()
    )

    $param = $SortingParameter[0]



    for ($i = 0; $i -lt $SortingParameter.Count; $i++) {
        $input = $input | Group-Object -Property $SortingParameter[$i]
        <# Action that will repeat until the condition is met #>
    }

    $srt = $MatchGroupsArray | Group-Object -Property $param

    # If there's only one or no SortingParameter left, perform final sorting and return
    if ($SortingParameter.Count -le 1) {
        $param = $SortingParameter[0]

        if ($TryVersionConvertForSorting -contains $param) {
            return $MatchGroupsArray | Sort-Object -Property {
                # Try to convert to version; if fail, use the original value
                try {
                    [Version]$_.($param)
                }
                catch {
                    $_.($param)
                }
            }
        }
        else {
            return $MatchGroupsArray | Sort-Object -Property $param
        }
    }

    # Perform grouping and sort each group separately
    $param = $SortingParameter[0]
    $groupedArray = $MatchGroupsArray | Group-Object -Property $param

    # Initialize the sorted array
    $sortedArray = @()

    foreach ($group in $groupedArray) {
        # Recursively sort each group using the rest of the SortingParameters
        $sortedGroup = Sort-MatchGroups -MatchGroupsArray $group.Group -SortingParameter $SortingParameter[1..($SortingParameter.Count - 1)] -TryVersionConvertForSorting $TryVersionConvertForSorting

        # Append the sorted group to the sorted array
        $sortedArray += $sortedGroup
    }

    return $sortedArray
}

function Sort-Hashtable {
    param (
        [Parameter(Mandatory=$true)]
        [Hashtable]$Hashtable,

        [Parameter(Mandatory=$false)]
        [bool]$TryTreatKeyAsPossibleVersion = $false
    )

    $sorted = [ordered]@{}

    # Sort hashtable by key
    $keys = $Hashtable.Keys
    if ($TryTreatKeyAsPossibleVersion) {
        $allKeysCanBeConvertedToVersion = $keys -cnotcontains $null -and ($keys | ForEach-Object {
            try {
                [version]$_ | Out-Null
                $true
            } catch {
                $false
            }
        }) -notcontains $false

        if ($allKeysCanBeConvertedToVersion) {
            $keys = $keys | Sort-Object -Property {[version]$_}
        } else {
            $keys = $keys | Sort-Object
        }
    } else {
        $keys = $keys | Sort-Object
    }

    foreach ($key in $keys) {
        $value = $Hashtable[$key]

        # If value is another hashtable, sort it too
        if ($value -is [Hashtable]) {
            $value = Sort-Hashtable -Hashtable $value -TryTreatKeyAsPossibleVersion $TryTreatKeyAsPossibleVersion
        }
        # If value is an array of hashtables, sort each hashtable
        elseif ($value -is [Array] -and $value[0] -is [Hashtable]) {
            $sortedArray = @()
            foreach ($item in $value) {
                $sortedArray += , (Sort-Hashtable -Hashtable $item -TryTreatKeyAsPossibleVersion $TryTreatKeyAsPossibleVersion)
            }
            $value = $sortedArray
        }

        $sorted[$key] = $value
    }

    return $sorted
}



function Group-CustomObjectArray {
    param (
        [Parameter(Mandatory=$true)]
        [Array]$InputArray,

        [Parameter(Mandatory=$true)]
        [Array]$GroupBy
    )

    # Initiate empty hashtable for grouping
    $groups = @{}

    foreach ($object in $InputArray) {
        $nestedGroup = $groups # Start at top level

        for ($i = 0; $i -lt $GroupBy.Count; $i++) {
            $property = $GroupBy[$i]
            $value = $object.$property

            # If it's the last property, add object to group
            if ($i -eq $GroupBy.Count - 1) {
                if (-not $nestedGroup.ContainsKey($value)) { 
                    $nestedGroup[$value] = @()
                }
                $nestedGroup[$value] += $object
            } else {
                # Otherwise, go deeper or create new group
                if (-not $nestedGroup.ContainsKey($value)) { 
                    $nestedGroup[$value] = @{} 
                }
                $nestedGroup = $nestedGroup[$value]
            }
        }
    }

    return Sort-Hashtable -Hashtable $groups -TryTreatKeyAsPossibleVersion $true
}

function NestedGroup-CustomObjectArray {
    param (
        [Parameter(Mandatory=$true)]
        [Array]$InputArray,

        [Parameter(Mandatory=$true)]
        [Array]$GroupBy
    )

    # Initiate empty hashtable for grouping
    $groups = @{}

    foreach ($object in $InputArray) {
        $nestedGroup = $groups # Start at top level

        for ($i = 0; $i -lt $GroupBy.Count; $i++) {
            $property = $GroupBy[$i]
            $value = $object.$property

            # If it's the last property, add object to group
            if ($i -eq $GroupBy.Count - 1) {
                if (-not $nestedGroup.ContainsKey($value)) { 
                    $nestedGroup[$value] = @()
                }
                $nestedGroup[$value] += $object
            } else {
                # Otherwise, go deeper or create new group
                if (-not $nestedGroup.ContainsKey($value)) { 
                    $nestedGroup[$value] = @{} 
                }
                $nestedGroup = $nestedGroup[$value]
            }
        }
    }

    return $groups
}

function NestedSort-Hashtable {
    param (
        [Parameter(Mandatory=$true)]
        [Hashtable]$Hashtable,

        [Parameter(Mandatory=$false)]
        [bool]$TryTreatKeyAsPossibleVersion = $false
    )

    $sorted = [ordered]@{}

    # Sort hashtable by key
    $keys = $Hashtable.Keys
    if ($TryTreatKeyAsPossibleVersion) {
        $allKeysCanBeConvertedToVersion = $keys -cnotcontains $null -and ($keys | ForEach-Object {
            try {
                [version]$_ | Out-Null
                $true
            } catch {
                $false
            }
        }) -notcontains $false

        if ($allKeysCanBeConvertedToVersion) {
            $keys = $keys | Sort-Object -Property {[version]$_}
        } else {
            $keys = $keys | Sort-Object
        }
    } else {
        $keys = $keys | Sort-Object
    }

    foreach ($key in $keys) {
        $value = $Hashtable[$key]

        # If value is another hashtable, sort it too
        if ($value -is [Hashtable]) {
            $value = Sort-Hashtable -Hashtable $value -TryTreatKeyAsPossibleVersion $TryTreatKeyAsPossibleVersion
        }
        # If value is an array of hashtables, sort each hashtable
        elseif ($value -is [Array] -and $value[0] -is [Hashtable]) {
            $sortedArray = @()
            foreach ($item in $value) {
                $sortedArray += , (Sort-Hashtable -Hashtable $item -TryTreatKeyAsPossibleVersion $TryTreatKeyAsPossibleVersion)
            }
            $value = $sortedArray
        }

        $sorted[$key] = $value
    }

    return $sorted
}

function Flatten-Groups {
    param (
        [Parameter(Mandatory=$true)]
        $GroupedHashtable
    )

    $result = @()

    foreach ($key in $GroupedHashtable.Keys) {
        $value = $GroupedHashtable[$key]

        if ($value -is [Array]) {
            # If value is an array of objects, add objects to result
            $result += $value
        } elseif ($value -is [Hashtable] -or $value -is [System.Collections.Specialized.OrderedDictionary]) {
            # If value is a hashtable or an ordered dictionary, recursively flatten groups
            $result += Flatten-Groups -GroupedHashtable $value
        }
    }

    return $result
}



function Initialize-DevToolPython {
    [Diagnostics.CodeAnalysis.SuppressMessage("PSUseApprovedVerbs","")]
    param (
        [ModuleScope]$Scope = [ModuleScope]::CurrentUser
    )
    # Check if the current process can execute in the desired scope
    if (-not(CanExecuteInDesiredScope -Scope $Scope))
    {
        return
    }

    $moduleName , $moduleVersion = Get-CurrentModule -MyInvocationMyCommand $MyInvocation.MyCommand
    $updatesDone = $false

    $contentText = "Python (PythonEmbeded)"

    Write-FormatedText -PrefixText "$moduleName" -ContentText "$contentText" -SuffixText "Check"
    if (-not(Get-Command "pythonw" -ErrorAction SilentlyContinue)) {
        Write-FormatedText -PrefixText "$moduleName" -ContentText "$contentText" -SuffixText "Download"
        $targetdir = "$($global:CoreeDevToolsRoot)\PythonEmbeded"
        $found = Find-Links -url "https://www.python.org/downloads/windows/"
        $AssetNameFilters = @("embed","amd64",".zip")
        $matchedUrl = Find-ItemsWithLists -InputItems $found -WhiteListMatch $AssetNameFilters
        $regexPattern = "-((\d+\.\d+\.\d+)([a-z]+\d+)*)-"
        $result = Find-MatchGroups -InputStrings $matchedUrl -RegexPattern $regexPattern
        $Nested = NestedGroup-CustomObjectArray -InputArray $result -GroupBy @("Match2","Match3")
        $NestedSort = NestedSort-Hashtable -Hashtable $Nested -TryTreatKeyAsPossibleVersion $true
        $flattened = Flatten-Groups -GroupedHashtable $NestedSort
        $latstreleaseversion = $flattened | Where-Object {$_.Match3 -eq ""} | Select-Object -Last 1

        $file = Get-RedirectDownload2 -Url "$($latstreleaseversion.OriginalItem)"

        Expand-Archive -Path $file -DestinationPath "$targetdir" -Force
        AddPathEnviromentVariable -Path "$targetdir" -Scope CurrentUser

        $filePath= "$($env:localappdata)\Microsoft\WindowsApps\$((Get-Command "python" -ErrorAction SilentlyContinue).Name)"
        if (Test-Path -Path $filePath -PathType Leaf) {
            Remove-Item -Path $filePath -Force
        }

        $filePath= "$($env:localappdata)\Microsoft\WindowsApps\$((Get-Command "python3" -ErrorAction SilentlyContinue).Name)"
        if (Test-Path -Path $filePath -PathType Leaf) {
            Remove-Item -Path $filePath -Force
        }

        if (Test-Path -Path "$targetdir\python.exe" -PathType Leaf) {
            #&runas /user:guest cmd /c mklink "$targetdir\python3.exe" "$targetdir\python.exe"
        }

        # need to reomve C:\Users\Valgrind\AppData\Local\Microsoft\WindowsApps
    } else {
        Write-FormatedText -PrefixText "$moduleName" -ContentText "$contentText" -SuffixText "Already available"
    }
    Write-FormatedText -PrefixText "$moduleName" -ContentText "$contentText" -SuffixText "Completed"

    return $updatesDone
}