Mind_Reader/setup-development/windows/upgrade-windows.ps1

214 lines
8.3 KiB
PowerShell
Raw Normal View History

<#
.synopsis
Dependency updater for Mind Reader on Windows.
This script expects to be run from Mind_Reader/setup-development
.description
Updates dependencies (NodeJS, Python, etc.), VSCode, NVDA
The script uses winget (A.K.A. "App Installer") to download and install the latest versions of each dependency, defined in winget/dependencies.json
Winget comes preinstalled on Windows 11 (21H2)/10 (21H1) or newer, and can be installed on Windows 10 1704+ through the Windows Store.
If you download Microsoft's developer VM, you have it!
As WinGet is built into Windows, it sidesteps any annoying third-party package managers, and is the lowest common denominator for package installation.
.link
https://github.com/We-Dont-Byte/Mind_Reader/
.parameter GitDir
Path to clone the git repo into (Default: $HOME/git/)
.parameter AllowAdministrator
Force-allow running this script as Administrator (not recommended, despite the frequent UAC prompts!)
.parameter NoPrompt
Disable all prompts for user input, and all waiting. (not recommended when combined with AllowAdministrator!)
.parameter Install
Force installation/upgrade of all modules, even if already present on the system.
.parameter DryRun
Perform a "dry run" of the script, changing directories and running commands, but without modifying anything.
.example
./upgrade-windows.ps1
Perform a default upgrade of all Mind Reader dependencies
.example
./upgrade-windows.ps1 -DryRun
Perform a dry run of the upgrade process, so you can evaluate what commands will be run
.example
./upgrade-windows.ps1 -NoPrompt
Don't prompt for user input when upgrading
.example
./upgrade-windows.ps1 -AllowAdministrator
Allow script to be run as Administrator
#>
param (
[switch]$AllowAdministrator, # Force allow installation as administrator
[switch]$NoPrompt, # Disable the 3-second wait and press-any-key prompt
[switch]$Install, # Perform all installations, even when commands are present
[switch]$DryRun, # Run script without installing
[switch]$NoWinget # Don't update dependdencies with winget
)
# .description
# Get-CommandAvailable: Checks whether a given command is available.
# If command is available, returns $false
function Get-CommandAvailable {
param ($command)
# Use a wildcard here so the command doesn't throw an exception we'd have to trycatch
# It's not a filthy hack if it's elegant!
RETURN (Get-Command -Name $command*)
}
#.description
# Invoke-Dryrun a powershell statement
function Invoke-Dryrun {
param ([string] $command)
$prompt = "> "
if ($DryRun) {
Write-Host "$prompt$command [dry]" -ForegroundColor darkgray
}
else {
Write-Host "$prompt$command" -ForegroundColor white
Invoke-Expression $command
}
}
#.description
# Reset-Path: Reload the Path environment variable
function Reset-Path {
Write-Output "Reloading Path..."
#* This code was created by user [mpen](https://stackoverflow.com/users/65387/mpen) on [StackOverflow](https://stackoverflow.com/a/31845512) and is used in accordance with Creative Commons CC BY-SA 3.0
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
}
# Check if Winget is available
if ( -not (Get-CommandAvailable winget) ) {
Write-Warning "It looks like winget isn't available.`n"
Write-Host "Update 'App Installer' through the Microsoft Store, or grab the '.msixbundle' from the winget-cli repository:"
Write-Host "( https://github.com/microsoft/winget-cli/releases/latest )`n" -ForegroundColor White
exit
}
# Check if the user ran the script with administrator privileges.
# Warn them.
if ( ([Security.Principal.WindowsIdentity]::GetCurrent().Groups -contains 'S-1-5-32-544') ) {
# If an administrator requests installation as administator,
# for example, to keep UAC prompts to a minimum, allow it.
if ($AllowAdministrator) {
# If you pass -AllowAdministrator -NoPrompt as an arg, you're very aware of the damage this script could do to your build env, and you just don't care
# The true chad of sysadmins.
if (!$NoPrompt) {
Write-Warning "Script was run as Administrator. Exit now if you didn't mean to do this!"
for ( $i = 3; $i -gt 0; $i--) {
Write-Host "Press Ctrl+C to exit. Continuing in $i...`r" -NoNewLine
Start-Sleep 1
}
Write-Host "Press any key to continue... "
[void][Console]::ReadKey(1) # Equivalent to Command Prompt's `pause` command
}
}
else {
# Throw a fatal errorOccurred if the user tries to run as administrator.
Throw "Script must be run as a normal user."
}
}
# Import the packages from dependencies.json (autogenerated file, do not edit!)
if ( -not $NoWinget) {
Write-Host "`nInstalling packages with winget..."
Invoke-Dryrun 'winget install Microsoft.VisualStudio.2022.BuildTools --override "--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"'
Invoke-Dryrun "winget import winget/dependencies.json"
# Reload the PATH, so we can use some of those sweet new commands we just installed
Reset-Path
}
# Check whether everything is available now:
$errorOccurred = 0
if ( -not (Get-CommandAvailable code) ) {
$errorOccurred += 1; Write-Host -ForegroundColor red "Visual Studio Code not available"
}
if ( -not (Get-CommandAvailable node) ) {
$errorOccurred += 2; Write-Host -ForegroundColor red "NodeJS not available"
}
if ( -not (Get-CommandAvailable npm ) ) {
$errorOccurred += 4; Write-Host -ForegroundColor red "Node Package Manager not available";
}
if ( $errorOccurred ) { exit }
# .description
# EnsureNodePackageInstalled:
# Checks for the presence of a cmdlet with a given name
# If it's not found, attempt to install it using npm
# If it's still not found, abort (this may not be good behavior?)
function EnsureNodePackageInstalled {
param (
[string[]]$command
)
if ( ($Install) -or -not (Get-CommandAvailable $command[0]) ) {
Write-Host "`nInstalling $($command[0])..."
Invoke-Dryrun "npm install -g $([string]$command)"
Reset-Path
if ( -not (Get-CommandAvailable $command[0])) {
Throw "$command failed to install. Aborting."
}
}
else {
Write-Host "`n$($command[0]) already installed." -ForegroundColor green
}
}
# Check if electron-rebuild is installed, if not, install it
EnsureNodePackageInstalled electron-rebuild
# These are useful (but not necessary) packages to have installed when working on new VSCode extensions
EnsureNodePackageInstalled yo, generator-code
# We're about to do some path traversal, so save the current directory
$prev_directory = $pwd
# install NodeJS dependencies for this extension
Write-Host "`nInstalling NodeJS Dependencies..."
Set-Location ..\..
Invoke-Dryrun "npm install"
# Run npm audit fix to upgrade vulnerable dependencies, except breaking changes.
Invoke-Dryrun "npm audit fix"
# if we're on a known VSCode version, go ahead and run electron-rebuild
switch -Regex (code --version) {
#?: Do we update this in the future, or stop maintaining it and remove this entire switch block?
"1\.67\.\d+" { $electronversion = "17.4.1"; break } # April 2022 update
"1\.66\.\d+" { $electronversion = "17.2.0"; break } # March 2022 update
default { $electronversion = $false } # Unknown update
}
if ( $electronversion ) {
Write-Host "`nRebuilding Electron for your version of VSCode..."
Invoke-Dryrun "electron-rebuild --version='$electronversion'"
Write-Host "Done!" -ForegroundColor green
}
else {
Write-Host "`nOpen Visual Studio Code, select the `"Help`" tab in the Toolbar, and go to `"About`".`nYou should see a page that looks like the following:" -ForegroundColor darkcyan
Write-Host " `(i`) Visual Studio Code`n`n Version: 1.66.2 `(user setup`)`n Commit: [Commit ID]`n Date: 2022-04-11T07:46:01.075Z`n Electron: 17.2.0`n [ ... ]" -ForegroundColor White
Write-Host "Note the Electron version `(17.2.0 in the above example`)." -ForegroundColor darkcyan
Write-Host "Run the command " -NoNewLine
Write-Host "electron-rebuild --version ELECTRON_VERSION" -NoNewLine -ForegroundColor green
Write-Host " in Mind Reader`'s root folder.`n"
}
# Return from whence we came
Set-Location $prev_directory
if ( -not $NoPrompt ) {
Write-Host "`nPress any key to exit."; [void][Console]::ReadKey(1)
}