Closed autarch closed 3 years ago
Full disclosure: I am by no means an expert with PowerShell. I've only ever used it for a handful of tasks, and this may actually be the most I've used it for any single purpose to date.
That being said, I'm fairly confident this will work as I intended it to (even if I think it could be done better), and have partially tested it on my own Windows machine.
To start with, you can always find the page containing all downloads associated with the most recently uploaded release by navigating to https://github.com/houseabsolute/ubi/releases/latest/ (Which will redirect you to the release-specific URL). For interacting with arbitrary internet endpoints using PowerShell, the Invoke-WebRequest
cmdlet is probably what you want.
From there, you may want to do some parsing to find what files are available to download for the release (In this case, I'm assuming the user isn't trying to download the source code, but the zip/tarball containing the pre-built binary), possibly query the user for which they want (I'm simply going to assume which file the user wants based on their platform), and then re-invoke Invoke-WebRequest
using the URL for that specific file.
To determine the URL for the specific file download, take the URL the initial request redirects to, and replace the string '/tag/' with '/download/', then append a '/' followed by the name of the specific file to the end. Since your file name scheme doesn't include the version number, you won't need to extract that from the redirected URL, but I've included a commented line that will do that if you need it. As such, your final request will be to a URL of the form [https://github.com/houseabsolute/ubi/releases/download/VERSION/ubi-SYSTEM_-x8664.FILE_EXTENSION]()
For versions of PowerShell prior to PowerShell Core (version 6.0, I believe), there really isn't a great way to detect the host OS using exclusively PowerShell and cmdlets (that don't require newer functionality), but that shouldn't be a huge deal, since there isn't really a great way to (natively) run versions of PowerShell prior to 6.0 on non-Windows systems. Therefore, it's probably safe to just hard-code the download for Windows in that case. Otherwise, there are automatic variables defined according to the platform, which we can test for and accordingly use the correct replacement strings for SYSTEM and FILE_EXTENSION as used above.
The following code should work for at least versions of PowerShell >= 4 on any of the 3 mainstream 64-bit desktop operating systems, downloading the proper file from this repository's latest release and saving it to the current directory with the filename unchanged (At least when run from the PowerShell command line itself).
# Try our best to make sure we allow any security protocol we might reasonably need; admittedly, this is a security risk, but I leave exactly how to handle this up to you.
# This should remain applied only until the end of the PowerShell session unless subsequently modified.
# It might be prudent to remember the initial setting and re-apply it when finished.
[Net.ServicePointManager]::SecurityProtocol = 'Ssl3,Tls,Tls11,Tls12,Tls3'
## This second way is probably the "more correct" method, but its also far more verbose.
## It's probably not worth using it until/unless you come across a scenario where the above assignment isn't good enough.
## [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13
# Request to be redirected to a page with downloads for the latest release.
$DlFileURL = (Invoke-WebRequest -URI "https://github.com/houseabsolute/ubi/releases/latest/").BaseResponse.ResponseUri.OriginalString
## This is one way to get the version from this particular URL if necessary.
## $DlFileVer = Split-Path -leaf "$DlFileURL"
# Determine platform and corresponding file extension for download.
If ($IsLinux){ $TargetOS = "Linux"; $DlFileExtension = "tar.gz" }
ElseIf ($IsMacOS){ $TargetOS = "Darwin"; $DlFileExtension = "tar.gz" }
ElseIf ($IsWindows -or $PSVersionTable.PSVersion.Major -lt 6){ $TargetOS = "Windows"; $DlFileExtension = "zip" }
# Yes, this could simply be inlined within the above if statements, but there may eventually be a use for having just specific parts of the file name.
$DlFileName = "ubi-$TargetOS-x86_64.$DlFileExtension"
# Replace 'tag' in the URL we're initially redirected to with 'download' so that requesting the URL again will specifically target the latest version.
# The slashes on both sides are included in both strings just to be certain that only whole path segments are replaced.
$DlFileURL = "$DlFileURL" -replace '/tag/','/download/'
# Append the part of the URL that will specify exactly which file to download among those from this latest release.
$DlFileURL = "$DlFileURL/$DlFileName"
# Make the request to download the correct file.
Invoke-WebRequest -URI "$DlFileURL" -OutFile "$DlFileName"
# I'm not actually sure how you'd like to specify the location to place this file in, so I'll leave that for you to decide and implement.
What you do after that is a little bit beyond the scope of my limited knowledge, and I'm not currently available to do too much digging, but I think you might end up using the Invoke-Item
cmdlet at some point to operate on the file you downloaded.
Older versions of Windows, like the version installed on my own machine, don't natively have a way to handle tar files (though that may not be a problem if you continue to use zip files for the windows releases), so it may be good to follow the second part of this answer from Stack Overflow. The same reasoning may also apply depending on the toolchain used during compilation, but I'm more focused on supporting older systems (and people who can't or won't update their OS).
If you don't want to deal with that, then you can probably use the Expand-Archive
cmdlet to unzip the compressed binary for Windows targets, but you'll still have to figure out how you'd like to handle tar-zipped files for other targets (Perhaps using something like (Get-Command TAR_BINARY_NAME).Path
to find whichever specific tar binary is standard each platform, then calling it with the correct parameters using Start-Process
).
Of course, all of this presumably relies on the user having granted PowerShell permission to run scripts on their machine.
Hopefully I've been able to at least give you a starting point.
Thanks very much for this!
I trimmed it down to something a bit simpler since I already have a shell script for everything that's not Windows. You can see the final result at https://github.com/houseabsolute/ubi/blob/master/bootstrap/bootstrap-ubi.ps1
Glad I could help!
It'd be nice if we could use ubi to install ubi, but that won't fly. So it'd be nice to provide a quick PowerShell bootstrap script instead.