pcsx-redux/mips.ps1
2023-02-28 20:02:34 -08:00

341 lines
12 KiB
PowerShell

<#
Copyright 2021 PCSX-Redux authors
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#>
if ((-not (Get-Variable PSVersionTable -Scope Global -ErrorAction SilentlyContinue)) -or ($PSVersionTable.PSVersion.Major -lt 5)) {
Write-Host "Your version of PowerShell is too old."
Write-Host "mips-ps requires a least PowerShell 5.0"
Write-Host "You need to download and install Windows Management Framework 5.0+"
exit
}
if (-not [Environment]::Is64BitOperatingSystem) {
Write-Host "The prebuilt mips toolchains can only work on a 64 bits version of Windows,"
Write-Host "but you're running a 32 bits version. Please install the 64 bits version of"
Write-Host "Windows and try again."
exit
}
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Get-AbsolutePath($Path) {
$Path = [System.IO.Path]::Combine(((pwd).path), ($Path))
$Path = [System.IO.Path]::GetFullPath($Path)
return $Path.TrimEnd("\/")
}
# Adds a path to the user's PATH environment variable.
function Add-Path($Path) {
$UserPath = [environment]::GetEnvironmentVariable("PATH", "User")
if ($UserPath -eq $NULL) {
return
}
foreach ($Fragment in $UserPath.split(";")) {
if ($Fragment -like $Path) {
return
}
}
[environment]::SetEnvironmentVariable("PATH", $UserPath + ";" + $Path, "User")
}
function MkDir-p($Path) {
$FullPath = "\\?\" + $Path
if (-not (Test-Path -Path $FullPath)) {
New-Item -ItemType directory -Path $FullPath | Out-Null
}
}
function Usage() {
Write-Host "Usage:"
Write-Host " mips install <version>"
Write-Host " mips use <version>"
Write-Host " mips ls"
Write-Host " mips ls-remote"
Write-Host " mips version"
Write-Host " mips self-install"
exit
}
function Download-Index($Path) {
$IndexFile = $Path + "/index.json"
$FullURL = $MipsBaseURL + "/index.json"
Invoke-WebRequest -UseBasicParsing -ContentType "application/octet-stream" -Uri $FullURL -OutFile $IndexFile
}
function Sort-Versions($Data) {
$Versions = @()
ForEach ($Version in $Data) {
[Int]$Major, [Int]$Minor, [Int]$Patch = $Version.version.TrimStart("v").Split(".")
$Key = $Major * 10000 + $Minor * 100 + $Patch
$Version | Add-Member Key $Key
$Versions += $Version
}
return $Versions | Sort-Object -Descending -Property Key
}
# Downloads the index, and assign a version number to it that can be easily sorted.
# This way doing mips install 8 will install the latest version of 8.
function Load-Index($Path) {
$IndexFile = $Path + "/index.json"
if (-not (Test-Path $IndexFile)) {
Download-Index($Path)
}
$RawData = (Get-Content $IndexFile) -join "`n" | ConvertFrom-Json
return Sort-Versions $RawData
}
function New-TempDir {
$TempDir = [System.IO.Path]::GetTempPath()
[string]$Random = [System.Guid]::NewGuid()
$TempDir = Join-Path $TempDir $Random
New-Item -ItemType Directory -Path $TempDir | Out-Null
return $TempDir
}
# Downloads the list of releases, and attempts to find a version that matches the
# one specified by $Version. Returns a structure with the information for that specific
# version. The index is this one: https://static.grumpycoder.net/pixel/mips/index.json
function Locate-Version($Version) {
$VersionString = "v" + $Version
$Version = $NULL
For ($run = 0; $run -le 1; $run++) {
$Index = Load-Index $cwd
ForEach ($Iterator in $Index) {
if ($Iterator.version.StartsWith($VersionString)) {
$Version = $Iterator
break
}
}
if ($Version -eq $NULL) {
Download-Index $cwd
} else {
$Version | Add-Member File $File
return $Version
}
}
Write-Host "Mips toolchain version $VersionString not found"
return $NULL
}
# Will change the symlink to another version of the toolchain. We're currently not checking if that
# version is indeed installed. TODO: check if the version is actually there.
function Use($Version) {
[string]$Version = $Version
if (!$Version.StartsWith("v")) {
$Installed = Get-ChildItem $VersionsPath | Select-Object Name
$Versions = @()
ForEach ($Iterator in $Installed) {
$Object = New-Object PSObject
$Object | Add-Member version $Iterator.Name
$Versions += $Object
}
$Versions = Sort-Versions $Versions
$Version = "v" + $Version
ForEach ($Iterator in $Versions) {
if ($Iterator.version.StartsWith($Version)) {
$Version = $Iterator.version
break
}
}
}
$VersionPath = $VersionsPath + "/" + $Version
if (Test-Path -Path $symlink) {
Remove-Item -Path $symlink -Recurse -Force
}
New-Item -Force -Path $symlink -ItemType Junction -Value $VersionPath
}
# Will attempt to download and install the version of the mips toolchain specified by $Version.
function Install($Version) {
$Version = Locate-Version $Version
if ($Version -eq $NULL) {
return $FALSE
}
$TempDir = New-TempDir
$OutputDir = $cwd + "/versions/" + $Version.version
$ToolchainURL = $MipsBaseURL + "g++-mipsel-none-elf-" + $Version.version.TrimStart("v") + ".zip"
$OutputToolchain = $TempDir + "/gcc.zip"
Write-Host "Downloading toolchain package from $ToolchainURL..."
Invoke-WebRequest -UseBasicParsing -ContentType "application/octet-stream" -Uri $ToolchainURL -OutFile $OutputToolchain
$GdbURL = $GdbBaseURL + "gdb-multiarch-" + $Version.gdb + ".zip"
$OutputGDB = $TempDir + "/gdb.zip"
Write-Host "Downloading gdb package from $GdbURL..."
Invoke-WebRequest -UseBasicParsing -ContentType "application/octet-stream" -Uri $GdbURL -OutFile $OutputGDB
Write-Host "Extracting toolchain package..."
Expand-Archive -Path $OutputToolchain -DestinationPath $OutputDir -Force
Write-Host "Extracting gdb package..."
Expand-Archive -Path $OutputGDB -DestinationPath $OutputDir -Force
Remove-Item -Path $OutputToolchain -Force | Out-Null
Remove-Item -Path $OutputGDB -Force | Out-Null
$VersionString = $Version.version
Use $VersionString
return $TRUE
}
$dest = Get-AbsolutePath ([Environment]::GetFolderPath('ApplicationData') + "/mips")
$me = $MyInvocation.MyCommand.Path
$MipsBaseURL = "https://static.grumpycoder.net/pixel/mips/"
$GdbBaseURL = "https://static.grumpycoder.net/pixel/gdb-multiarch-windows/"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$MyURI = "https://raw.githubusercontent.com/grumpycoders/pcsx-redux/main/mips.ps1"
# Globals for PowerShell behavior
$ProgressPreference = "SilentlyContinue"
$ErrorActionPreference = "stop"
# If we're invoked from the installer shortcut, we're going to redownload ourselves
# and install ourselves. That's a bit redundant, but, sure.
if ($MyInvocation.InvocationName -eq "&") {
$me = [System.IO.Path]::GetTempFileName()
Invoke-WebRequest -Uri $MyURI -OutFile $me
$cmd = "self-install"
$symlink = $dest + "/mips"
$VersionsPath = $dest + "/versions"
} else {
$cwd = Get-AbsolutePath (Split-Path $me)
$symlink = $cwd + "/mips"
$VersionsPath = $cwd + "/versions"
$cmd = $args[0]
if ($args.Length -eq 0) {
Add-Type -AssemblyName System.Windows.Forms
$installform = New-Object system.Windows.Forms.Form
$installform.Text = "MIPS Toolchain Installer"
$installform.Width = 400
$installform.Height = 200
$installform.StartPosition = "CenterScreen"
$installform.FormBorderStyle = "FixedDialog"
$installform.MaximizeBox = $FALSE
$installform.MinimizeBox = $FALSE
$installform.TopMost = $TRUE
$installform.ShowInTaskbar = $FALSE
$installform.TopLevel = $TRUE
$label = New-Object System.Windows.Forms.Label
$label.Text = "Select a version of the toolchain to install:"
$label.Location = New-Object System.Drawing.Point(10, 10)
$label.Width = 360
$installform.Controls.Add($label)
$list = New-Object System.Windows.Forms.ComboBox
$list.Location = New-Object System.Drawing.Point(10, 40)
$list.Width = 360
$list.DropDownStyle = "DropDownList"
$installform.Controls.Add($list)
$acceptButton = New-Object System.Windows.Forms.Button
$acceptButton.Text = "Install"
$acceptButton.Location = New-Object System.Drawing.Point(10, 70)
$acceptButton.Width = 360
$acceptButtonClick = {
$installform.Hide()
$installform.Close() | Out-Null
$toinstall = $list.Text
Install $toinstall.TrimStart("v") | Out-Null
}
$acceptButton.Add_Click($acceptButtonClick)
$installform.Controls.Add($acceptButton)
$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Text = "Cancel"
$cancelButton.Location = New-Object System.Drawing.Point(10, 100)
$cancelButton.Width = 360
$cancelButtonClick = {
$installform.Close() | Out-Null
}
$cancelButton.Add_Click($cancelButtonClick)
$installform.Controls.Add($cancelButton)
Download-Index $cwd
Load-Index $cwd | Sort-Object -Descending -Property Key | ForEach-Object {
$list.Items.Add($_.version) | Out-Null
}
$list.SelectedIndex = 0
$installform.ShowDialog() | Out-Null
return
}
}
switch ($cmd) {
"install" {
if ($args[1] -eq $NULL) {
Usage
}
Install $args[1] | Out-Null
}
"use" {
if ($args[1] -eq $NULL) {
Usage
}
Use $args[1] | Out-Null
}
"ls" {
Get-ChildItem $VersionsPath | Select-Object Name
}
"ls-remote" {
Download-Index $cwd
Load-Index $cwd | Sort-Object -Property Key | Select-Object version
}
"version" {
Write-Host "v0.2.0"
}
"self-install" {
if ($args[1] -ne $NULL) {
$dest = $args[1]
}
if ($cwd -like $dest) {
Write-Host "This is already installed."
} else {
Write-Host "Installing..."
while ($dest -match " ") {
Write-Host "The installation path of the mips toolchain contains spaces. This is not supported."
Write-Host "Please select a different folder for the installation."
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$folderdialog = New-Object System.Windows.Forms.FolderBrowserDialog
$folderdialog.Description = "Select an installation folder for the mips tool and toolchains."
$folderdialog.rootfolder = "MyComputer"
$folderdialog.SelectedPath = $initialDirectory
if ($folderdialog.ShowDialog() -eq "OK") {
$dest = $folderdialog.SelectedPath
} else {
Write-Host "Installation aborted."
return
}
}
MkDir-p $dest
MkDir-p $VersionsPath
Copy-Item -Force $me $dest/mips.ps1
Set-Content -Path $dest/mips.cmd -Value "@PowerShell -ExecutionPolicy Unrestricted %~dp0/mips.ps1 %*"
Add-Path $dest
Add-Path $symlink\bin
Write-Host "Done. Open a new console and type mips."
}
}
default {
Write-Host "Unknown command $cmd"
Usage
}
}