9 changed files with 1545 additions and 1258 deletions
@ -1,269 +1,374 @@
|
||||
|
||||
#launch example |
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/bin/getzig.cmd' -OutFile 'getzig.cmd'; Start-Process 'cmd.exe' -ArgumentList @('/c', 'getzig.cmd') -NoNewWindow -Wait" |
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/bin/getzig.cmd' -OutFile 'getzig.cmd'; Start-Process 'getzig.cmd' -NoNewWindow -Wait" |
||||
|
||||
#Join-Path using verbose method to support powershell 5? |
||||
#$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.." |
||||
$outbase = $PSScriptRoot |
||||
$outbase = Resolve-Path -Path $outbase |
||||
Write-host "Base folder: $outbase" |
||||
$toolsfolder = Join-Path -Path $outbase -ChildPath "tools" |
||||
if (-not(Test-Path -Path $toolsfolder -PathType Container)) { |
||||
#create folder - (can include missing intermediaries) |
||||
New-Item -Path $toolsfolder -ItemType Directory |
||||
} |
||||
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" |
||||
$zigexe = Join-Path $zigfolder "zig.exe" |
||||
$releasearchive = "zig-x86_64-windows-0.15.1.zip" ;#zip on windows, tarball on every other platform |
||||
Write-Output "powershell version: $($PSVersionTable.PSVersion)" |
||||
|
||||
if (Get-Command $zigexe -ErrorAction SilentlyContinue) { |
||||
Write-Host "zig.exe is installed in tools/zig" |
||||
$zigv = tools/zig/zig.exe version 2>&1 |
||||
$stdout = $zigv | Where-Object {$_ -is [string]} |
||||
$stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
if ($stderr) { |
||||
Write-Host "Unexpected output from tools/zig/zig.exe: $stderr" |
||||
Write-Host "Consider deleting tools/zig and re-downloading" |
||||
} else { |
||||
Write-Host "tools/zig/zig.exe version is: $stdout" |
||||
} |
||||
exit |
||||
} |
||||
|
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is available" |
||||
} else { |
||||
Write-Host "minisign is missing. Will attempt to install using winget." |
||||
#Find-Module/Install-Module: older mechanism, available in powershell |
||||
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? |
||||
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client |
||||
if (${wgclient}.Length -eq 0) { |
||||
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." |
||||
Install-PackageProvider -Name NuGet -Force |
||||
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy |
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
#Applies to all versions of PowerShell for the user, and is persistent for current user. |
||||
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted |
||||
} |
||||
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery |
||||
Repair-WinGetPackageManager |
||||
import-module -name Microsoft.Winget.client |
||||
|
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted |
||||
} |
||||
} else { |
||||
Write-Host "Microsoft.WinGet.Client is available" |
||||
} |
||||
$wingetversion = (Find-WinGetPackage jedisct1.minisign).Version |
||||
if ($wingetversion) { |
||||
Write-Host "Installing minisign version: ${wingetversion}" |
||||
Install-WinGetPackage -Id "jedisct1.minisign" |
||||
} else { |
||||
Write-Host "Failed to find minisign using winget" |
||||
exit |
||||
} |
||||
#refreshing the current session's path should make the new command available (required for powershell 5 at least) |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is now available" |
||||
} else { |
||||
Write-Host "minisign is still not available" |
||||
#if we automatically relaunch - we could get stuck in a loop - ask user. |
||||
$response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N" |
||||
#if ($PSVersionTable.PSEdition -eq "Desktop") { |
||||
#powershell.exe |
||||
#} else { |
||||
#pwsh.exe |
||||
#} |
||||
if ($response -ieq "y") { |
||||
Start-Process 'getzig.cmd' -NoNewWindow -Wait |
||||
} |
||||
exit |
||||
} |
||||
} |
||||
|
||||
$zigpubkey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U" |
||||
$mirrors_url = "https://ziglang.org/download/community-mirrors.txt" |
||||
$mirrors_response = $(Invoke-WebRequest -Uri $mirrors_url) |
||||
if ($mirrors_response.StatusCode -eq 200) { |
||||
#https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip |
||||
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") |
||||
$mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n" |
||||
#$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry |
||||
$mirror_array += "https://ziglang.org" #main site |
||||
|
||||
$dict_mirrors = [ordered]@{} |
||||
$host_list = @() #same ordering as dict_mirrors |
||||
foreach ($mirror in $mirror_array) { |
||||
$uri = New-Object System.Uri($mirror) |
||||
$hostname = $uri.Host |
||||
$dict_mirrors[$hostname] = @{} |
||||
$dict_mirrors[$hostname]["uri"] = $mirror |
||||
$dict_mirrors[$hostname]["latency"] = 888888 ;#default |
||||
$host_list += $hostname |
||||
#write-host "Host name: $hostname" |
||||
} |
||||
#write-host "dict: $($dict_mirrors | out-String)" |
||||
write-host "host_list: $host_list" |
||||
$automation_name = "punkshell+julian@precisium.com.au_target_by_latency" |
||||
|
||||
|
||||
#test-netconnection progressbar seems not-so-well-behaved (prog bar lingers) |
||||
#test-netconnection a function not cmdlet? Seems to need setting at global level |
||||
$OriginalProgressPreference = $Global:ProgressPreference |
||||
$Global:ProgressPreference = 'SilentlyContinue' |
||||
#temporary dev download source |
||||
$ihost = "10.30.30.107" |
||||
$imirror = "http://10.30.30.107/jn/punkbin/raw/branch/master/win32-x86_64/tools" |
||||
$itrace = test-netconnection $ihost -Hops 6 -TraceRoute -ErrorAction Ignore |
||||
if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) { |
||||
$host_list += $ihost |
||||
$dict_mirrors[$ihost] = @{} |
||||
$dict_mirrors[$ihost]["latency"] = 1 |
||||
$dict_mirrors[$ihost]["uri"] = $imirror |
||||
} |
||||
$trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore |
||||
$Global:ProgressPreference = $OriginalProgressPreference |
||||
|
||||
if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) { |
||||
$dict_mirrors["gitea1.intx.com.au"]["latency"] = 2 |
||||
#short-circuit for hosts very near gitea1.intx.com.au |
||||
#don't even test others. This is primarily for hosts at intx.com.au and associated entities - which are more likely to use punkshell than anyone else. |
||||
} else { |
||||
if ($PSVersionTable.PSEdition -eq "Desktop") { |
||||
#powershell.exe |
||||
#we seem to need -ErrorAction Ignore for bad/unresponsive host entries - but unlike with pwsh, we don't get any corresponding entry in the test_results, and -Quiet doesn't seem to give us results either REVIEW |
||||
$test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore |
||||
for ($i = 0; $i -lt $test_results.Count; $i++) { |
||||
$result = $test_results[$i] |
||||
if ($result) { |
||||
$targethost = $result.Address |
||||
if ($result.StatusCode -eq 0) { |
||||
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime |
||||
} else { |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} else { |
||||
$targethost = $host_list[$i] |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} |
||||
} else { |
||||
#pwsh.exe |
||||
$test_results = Test-Connection -TargetName $host_list -Count 1 -Ipv4 -Detailed -TcpPort 443 -Quiet |
||||
for ($i = 0; $i -lt $test_results.Count; $i++) { |
||||
$result = $test_results[$i] |
||||
if ($result) { |
||||
$targethost = $result.Target |
||||
if ($result.Status -eq "Success") { |
||||
$dict_mirrors[$targethost]["latency"] = $result.Latency |
||||
} else { |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} else { |
||||
$targethost = $host_list[$i] |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
$list_mirror_dicts = @() |
||||
#write-host "dict tested: $($dict_mirrors | Out-String)" |
||||
foreach ($key in $dict_mirrors.Keys) { |
||||
$list_mirror_dicts += $($dict_mirrors[$key]) |
||||
} |
||||
#need to ensure latency cast to integer (on powershell 5 at least) |
||||
$sorted_mirror_dicts = $list_mirror_dicts | Sort-Object -Property { [int]$_.latency } |
||||
#Write-Host "Sorted by latency: $($sorted_mirror_dicts | Format-Table -AutoSize | Out-String)" |
||||
Write-Host "Sorted by latency: $($sorted_mirror_dicts | Out-String)" |
||||
|
||||
foreach ($hostinfo in $sorted_mirror_dicts) { |
||||
$uristring = $hostinfo.uri |
||||
if ($uristring -eq "https://ziglang.org") { |
||||
$full_uristring = "${uristring}/download/0.15.1/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/download/0.15.1/${releasearchive}.minisig?source=${automation_name}" |
||||
} else { |
||||
$full_uristring = "${uristring}/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/${releasearchive}.minisig?source=${automation_name}" |
||||
} |
||||
Write-Host "Downloading zig from $full_uristring" |
||||
#$uriobj = [uri]$full_uristring |
||||
#$lastSegment = $uriobj.Segments[-1] |
||||
#$outfile = Join-Path $toolsfolder -ChildPath $lastSegment |
||||
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive |
||||
Write-Host "Download to: $outfile" |
||||
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile |
||||
|
||||
if (-not(Test-Path -Path $outfile -PathType Leaf)) { |
||||
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
Write-Host "Downloading minisig signature from $sig_uristring" |
||||
Invoke-WebRequest -Uri $sig_uristring -Outfile "${outfile}.minisig" |
||||
if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) { |
||||
write-Host "Failed to download minisig from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
|
||||
write-host "downloaded $outfile and ${outfile}.minisig - validating signature..." |
||||
#validate releasearchive (tarball/zip) |
||||
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 |
||||
$stdout = $sigresult | Where-Object {$_ -is [string]} |
||||
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
$is_valid = $false |
||||
if ($stderr) { |
||||
write-host "Signature validation failed with message: $stderr" |
||||
} else { |
||||
if (($stdout | Out-String).Contains("signature verified")) { |
||||
write-host $stdout |
||||
$is_valid = $true |
||||
} else { |
||||
write-host "Unexpected output from minisign: $stdout" |
||||
write-host "Did not contain 'signature verified'" |
||||
} |
||||
} |
||||
if (-not($is_valid)) { |
||||
write-Host "Couldn't verify signature from download site $uristring" |
||||
Remove-Item -Path $outfile -ErrorAction SilentlyContinue |
||||
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue |
||||
continue |
||||
} |
||||
|
||||
Write-Host "Signature OK - extracting archive ..." |
||||
#Expand-Archive -path $outfile -DestinationPath $toolsfolder -Force #This is *insanely* (many minutes vs seconds) slow on powershell 5 at least - we get a progress meter, but it's too high a price to pay. |
||||
# ------------------------------------- |
||||
Add-Type -Assembly "System.IO.Compression.Filesystem" |
||||
[System.IO.Compression.Zipfile]::ExtractToDirectory($outfile, $toolsfolder) |
||||
Write-Host " - archive extracted." |
||||
#We *intermittently* get permission errors when trying to rename the resulting folder (possibly also if we try to delete the zip file immediately) |
||||
#There seems to be some sort of lock held after ExtractToDirectory (possibly AV related) |
||||
#https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory |
||||
[GC]::Collect() |
||||
[GC]::WaitForPendingFinalizers() |
||||
# ------------------------------------- |
||||
|
||||
#Remove-Item -Path "$outfile" |
||||
$zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive) |
||||
#Rename-Item -Path |
||||
#write-host "zip_rootname: $zip_rootname" |
||||
write-host "moving $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) to ${zigfolder}" |
||||
Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder |
||||
Write-Host "Zig installed in ${zigfolder}" |
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
$v = Invoke-Expression "$zigexe version" |
||||
Write-Host "ZIG VERSION: ${v}" |
||||
$test_ok = 1 ;#todo |
||||
if ($test_ok) { |
||||
break |
||||
} |
||||
} |
||||
|
||||
} else { |
||||
Write-Host "Unable to retrieve list of zig community mirrors from $mirrors_url" |
||||
} |
||||
|
||||
#launch example |
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/bin/getzig.cmd' -OutFile 'getzig.cmd'; Start-Process 'cmd.exe' -ArgumentList @('/c', 'getzig.cmd') -NoNewWindow -Wait" |
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/bin/getzig.cmd' -OutFile 'getzig.cmd'; Start-Process 'getzig.cmd' -NoNewWindow -Wait" |
||||
|
||||
#Join-Path using verbose method to support powershell 5? |
||||
#$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.." |
||||
$outbase = $PSScriptRoot |
||||
$outbase = Resolve-Path -Path $outbase |
||||
Write-host "Base folder: $outbase" |
||||
$toolsfolder = Join-Path -Path $outbase -ChildPath "tools" |
||||
if (-not(Test-Path -Path $toolsfolder -PathType Container)) { |
||||
#create folder - (can include missing intermediaries) |
||||
New-Item -Path $toolsfolder -ItemType Directory |
||||
} |
||||
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" |
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
# $releasearchive = "zig-x86_64-windows-0.15.1.zip" ;#zip on windows, tarball on every other platform |
||||
$releasearchive = "zig-x86_64-windows-0.16.0-dev.254+6dd0270a1.zip" |
||||
Write-Output "powershell version: $($PSVersionTable.PSVersion)" |
||||
|
||||
if (Get-Command $zigexe -ErrorAction SilentlyContinue) { |
||||
$relative_zigfolder = Resolve-Path -Path $zigfolder -RelativeBasePath $outbase -Relative |
||||
Write-Host "zig.exe is installed in $relative_zigfolder" |
||||
$zigv = & $zigexe version 2>&1 |
||||
$stdout = $zigv | Where-Object {$_ -is [string]} |
||||
$stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
if ($stderr) { |
||||
Write-Host "Unexpected output from ${zigexe}: $stderr" |
||||
Write-Host "Consider deleting $zigexe and re-downloading" |
||||
} else { |
||||
Write-Host "$zigexe version is: $stdout" |
||||
} |
||||
exit |
||||
} |
||||
|
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is available" |
||||
} else { |
||||
Write-Host "minisign is missing. Will attempt to install using winget." |
||||
#Find-Module/Install-Module: older mechanism, available in powershell |
||||
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? |
||||
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client |
||||
if (${wgclient}.Length -eq 0) { |
||||
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." |
||||
Install-PackageProvider -Scope CurrentUser -Name NuGet -Force |
||||
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy |
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
#Applies to all versions of PowerShell for the user, and is persistent for current user. |
||||
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted |
||||
} |
||||
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery |
||||
Repair-WinGetPackageManager |
||||
import-module -name Microsoft.Winget.client |
||||
|
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted |
||||
} |
||||
} else { |
||||
Write-Host "Microsoft.WinGet.Client is available" |
||||
} |
||||
$wingetversion = (Find-WinGetPackage jedisct1.minisign).Version |
||||
if ($wingetversion) { |
||||
Write-Host "Installing minisign version: ${wingetversion}" |
||||
Install-WinGetPackage -Id "jedisct1.minisign" |
||||
} else { |
||||
Write-Host "Failed to find minisign using winget" |
||||
exit |
||||
} |
||||
#refreshing the current session's path should make the new command available (required for powershell 5 at least) |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is now available" |
||||
} else { |
||||
Write-Host "minisign is still not available" |
||||
#if we automatically relaunch - we could get stuck in a loop - ask user. |
||||
$response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N" |
||||
#if ($PSVersionTable.PSEdition -eq "Desktop") { |
||||
#powershell.exe |
||||
#} else { |
||||
#pwsh.exe |
||||
#} |
||||
if ($response -ieq "y") { |
||||
Start-Process 'getzig.cmd' -NoNewWindow -Wait |
||||
} |
||||
exit |
||||
} |
||||
} |
||||
|
||||
#extract_zip to be called only after sig verified |
||||
; |
||||
function extractZip { |
||||
[CmdletBinding()] |
||||
param( |
||||
[Parameter(Mandatory=$true, Position = 0)][string] $releasearchive, |
||||
[Parameter(Mandatory=$true, Position = 1)] [string] $toolsfolder |
||||
) |
||||
Add-Type -Assembly "System.IO.Compression.Filesystem" |
||||
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive |
||||
|
||||
$zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive) |
||||
if (-not ($zip_rootname.Contains("zig"))) { |
||||
write-host "sanity check on zip_rootname '$zip_rootname' failed - aborting" |
||||
exit 1 |
||||
} |
||||
$zip_extraction_folder = Join-Path -Path $toolsfolder -ChildPath $zip_rootname |
||||
if (Test-Path -Path $zip_extraction_folder -PathType Container) { |
||||
write-host "Existing folder found at $zip_extraction_folder - removing folder prior to extraction" |
||||
Remove-Item -Path $zip_extraction_folder -Recurse -Force -ErrorAction SilentlyContinue |
||||
} |
||||
#Expand-Archive -path $outfile -DestinationPath $toolsfolder -Force #This is *insanely* (many minutes vs seconds) slow on powershell 5 at least - we get a progress meter, but it's too high a price to pay. |
||||
# ------------------------------------- |
||||
[System.IO.Compression.Zipfile]::ExtractToDirectory($outfile, $toolsfolder) |
||||
Write-Host " - archive extracted." |
||||
if (-not (Test-Path -Path $zip_extraction_folder -PathType Container)) { |
||||
write-host "Failed to verify extraction as folder at $zip_extraction_folder" |
||||
exit 1 |
||||
} |
||||
|
||||
|
||||
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" |
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
|
||||
$retries = 10 |
||||
$exe_missing = $true #missing until tested as a found leaf |
||||
$sleep_time = 2 |
||||
while (($retries -gt 0) -and $exe_missing) { |
||||
$retries -= 1 |
||||
#We *intermittently* get permission errors when trying to rename the resulting folder (possibly also if we try to delete the zip file immediately) |
||||
#There seems to be some sort of lock held after ExtractToDirectory (possibly AV related) |
||||
#https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory |
||||
|
||||
#In some cases just the GC was enough.. but in other cases even sleep 3 seconds + GC didn't work |
||||
#sleep of 5 seems more reliable - but the size of the required delay may depend on what is running on the system, |
||||
# and the size of the extracted folder etc. |
||||
#Rather than use a large sleep to cover all cases - we use a limited retry loop with a somewhat shorter sleep e.g 2 |
||||
Write-Host "waiting $sleep_time seconds and also running GC to allow locks to clear. Max remaining retries: $retries" |
||||
start-sleep -Seconds $sleep_time |
||||
|
||||
[GC]::Collect() |
||||
[GC]::WaitForPendingFinalizers() |
||||
# ------------------------------------- |
||||
#Remove-Item -Path "$outfile" |
||||
#write-host "zip_rootname: $zip_rootname" |
||||
write-host "Attempting to move $zip_extraction_folder to ${zigfolder}" |
||||
Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder -ErrorAction SilentlyContinue |
||||
if (-not $?) { |
||||
write-host "Renaming extracted folder into place at $zigfolder failed" |
||||
write-host " - error message: $($error[0].Exception.Message)" |
||||
} |
||||
if (Test-Path -Path $zigexe -PathType leaf) { |
||||
$exe_missing = $false |
||||
} |
||||
} |
||||
|
||||
if (Test-Path -Path $zigexe -PathType leaf) { |
||||
Write-Host "Zig installed in ${zigfolder}" |
||||
return $true |
||||
} else { |
||||
Write-Host "Failed to install as $zigexe" |
||||
return $false |
||||
} |
||||
} |
||||
|
||||
|
||||
$zigpubkey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U" |
||||
|
||||
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive |
||||
$sigfile = "${outfile}.minisig" |
||||
$download_required = $true #default assumption |
||||
if (Test-Path -Path $outfile -PathType Leaf) { |
||||
if (Test-Path -Path $sigfile) { |
||||
write-host "Found existing $outfile and ${outfile}.minisig - validating signature..." |
||||
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 |
||||
$stdout = $sigresult | Where-Object {$_ -is [string]} |
||||
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
$is_valid = $false |
||||
if ($stderr) { |
||||
write-host "Signature validation failed with message: $stderr" |
||||
} else { |
||||
if (($stdout | Out-String).Contains("signature verified")) { |
||||
write-host $stdout |
||||
$is_valid = $true |
||||
} else { |
||||
write-host "Unexpected output from minisign: $stdout" |
||||
write-host "Did not contain 'signature verified'" |
||||
} |
||||
} |
||||
if (-not($is_valid)) { |
||||
write-Host "Couldn't verify signature of existing $outfile with $outfile.minisig" |
||||
Remove-Item -Path $outfile -ErrorAction SilentlyContinue |
||||
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue |
||||
} else { |
||||
$download_required = $false |
||||
} |
||||
} |
||||
} |
||||
if (-not $download_required) { |
||||
write-host "Existing zip and zip.minisig ok - download not required" |
||||
Write-Host "Signature OK - extracting existing archive ..." |
||||
$null = extractZip $releasearchive $toolsfolder |
||||
|
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
$v = Invoke-Expression "$zigexe version" |
||||
Write-Host "ZIG VERSION: ${v}" |
||||
exit 0 |
||||
} |
||||
|
||||
$mirrors_url = "https://ziglang.org/download/community-mirrors.txt" |
||||
$mirrors_response = $(Invoke-WebRequest -Uri $mirrors_url) |
||||
if ($mirrors_response.StatusCode -eq 200) { |
||||
#https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip |
||||
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") |
||||
$mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n" |
||||
#$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry |
||||
$mirror_array += "https://ziglang.org" #main site |
||||
|
||||
$dict_mirrors = [ordered]@{} |
||||
$host_list = @() #same ordering as dict_mirrors |
||||
foreach ($mirror in $mirror_array) { |
||||
$uri = New-Object System.Uri($mirror) |
||||
$hostname = $uri.Host |
||||
$dict_mirrors[$hostname] = @{} |
||||
$dict_mirrors[$hostname]["uri"] = $mirror |
||||
$dict_mirrors[$hostname]["latency"] = 888888 ;#default |
||||
$host_list += $hostname |
||||
#write-host "Host name: $hostname" |
||||
} |
||||
#write-host "dict: $($dict_mirrors | out-String)" |
||||
write-host "host_list: $host_list" |
||||
$automation_name = "punkshell+julian@precisium.com.au_target_by_latency" |
||||
|
||||
|
||||
#test-netconnection progressbar seems not-so-well-behaved (prog bar lingers) |
||||
#test-netconnection a function not cmdlet? Seems to need setting at global level |
||||
$OriginalProgressPreference = $Global:ProgressPreference |
||||
$Global:ProgressPreference = 'SilentlyContinue' |
||||
#temporary dev download source |
||||
$ihost = "10.30.30.107" |
||||
$imirror = "http://10.30.30.107/jn/punkbin/raw/branch/master/win32-x86_64/tools" |
||||
$itrace = test-netconnection $ihost -Hops 6 -TraceRoute -ErrorAction Ignore |
||||
if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) { |
||||
$host_list += $ihost |
||||
$dict_mirrors[$ihost] = @{} |
||||
$dict_mirrors[$ihost]["latency"] = 1 |
||||
$dict_mirrors[$ihost]["uri"] = $imirror |
||||
} |
||||
$trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore |
||||
$Global:ProgressPreference = $OriginalProgressPreference |
||||
|
||||
if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) { |
||||
$dict_mirrors["gitea1.intx.com.au"]["latency"] = 2 |
||||
#short-circuit for hosts very near gitea1.intx.com.au |
||||
#don't even test others. This is primarily for hosts at intx.com.au and associated entities - which are more likely to use punkshell than anyone else. |
||||
} else { |
||||
if ($PSVersionTable.PSEdition -eq "Desktop") { |
||||
#powershell.exe |
||||
#we seem to need -ErrorAction Ignore for bad/unresponsive host entries - but unlike with pwsh, we don't get any corresponding entry in the test_results, and -Quiet doesn't seem to give us results either REVIEW |
||||
$test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore |
||||
for ($i = 0; $i -lt $test_results.Count; $i++) { |
||||
$result = $test_results[$i] |
||||
if ($result) { |
||||
$targethost = $result.Address |
||||
if ($result.StatusCode -eq 0) { |
||||
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime |
||||
} else { |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} else { |
||||
$targethost = $host_list[$i] |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} |
||||
} else { |
||||
#pwsh.exe |
||||
$test_results = Test-Connection -TargetName $host_list -Count 1 -Ipv4 -Detailed -TcpPort 443 -Quiet |
||||
for ($i = 0; $i -lt $test_results.Count; $i++) { |
||||
$result = $test_results[$i] |
||||
if ($result) { |
||||
$targethost = $result.Target |
||||
if ($result.Status -eq "Success") { |
||||
$dict_mirrors[$targethost]["latency"] = $result.Latency |
||||
} else { |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} else { |
||||
$targethost = $host_list[$i] |
||||
$dict_mirrors[$targethost]["latency"] = 999999 |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
$list_mirror_dicts = @() |
||||
#write-host "dict tested: $($dict_mirrors | Out-String)" |
||||
foreach ($key in $dict_mirrors.Keys) { |
||||
$list_mirror_dicts += $($dict_mirrors[$key]) |
||||
} |
||||
#need to ensure latency cast to integer (on powershell 5 at least) |
||||
$sorted_mirror_dicts = $list_mirror_dicts | Sort-Object -Property { [int]$_.latency } |
||||
#Write-Host "Sorted by latency: $($sorted_mirror_dicts | Format-Table -AutoSize | Out-String)" |
||||
Write-Host "Sorted by latency: $($sorted_mirror_dicts | Out-String)" |
||||
|
||||
foreach ($hostinfo in $sorted_mirror_dicts) { |
||||
$uristring = $hostinfo.uri |
||||
if ($uristring -eq "https://ziglang.org") { |
||||
$full_uristring = "${uristring}/download/0.15.1/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/download/0.15.1/${releasearchive}.minisig?source=${automation_name}" |
||||
} else { |
||||
$full_uristring = "${uristring}/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/${releasearchive}.minisig?source=${automation_name}" |
||||
} |
||||
#download the minisig first - because if that fails, we should move on without trying the larger download |
||||
Write-Host "Downloading minisig signature from $sig_uristring" |
||||
Invoke-WebRequest -Uri $sig_uristring -Outfile "${outfile}.minisig" |
||||
if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) { |
||||
write-Host "Failed to download minisig signature from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
|
||||
Write-Host "Downloading zig distribution from $full_uristring" |
||||
Write-Host "Download to: $outfile" |
||||
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile |
||||
|
||||
if (-not(Test-Path -Path $outfile -PathType Leaf)) { |
||||
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
|
||||
write-host "downloaded $outfile and ${outfile}.minisig - validating signature..." |
||||
#validate releasearchive (tarball/zip) |
||||
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 |
||||
$stdout = $sigresult | Where-Object {$_ -is [string]} |
||||
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
$is_valid = $false |
||||
if ($stderr) { |
||||
write-host "Signature validation failed with message: $stderr" |
||||
} else { |
||||
if (($stdout | Out-String).Contains("signature verified")) { |
||||
write-host $stdout |
||||
$is_valid = $true |
||||
} else { |
||||
write-host "Unexpected output from minisign: $stdout" |
||||
write-host "Did not contain 'signature verified'" |
||||
} |
||||
} |
||||
if (-not($is_valid)) { |
||||
write-Host "Couldn't verify signature from download site $uristring" |
||||
Remove-Item -Path $outfile -ErrorAction SilentlyContinue |
||||
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue |
||||
continue |
||||
} |
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------- |
||||
Write-Host "Signature OK - extracting downloaded archive ..." |
||||
$null = extractZip $releasearchive $toolsfolder |
||||
|
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
$v = Invoke-Expression "$zigexe version" |
||||
Write-Host "ZIG VERSION: ${v}" |
||||
|
||||
$test_ok = 1 ;#todo |
||||
if ($test_ok) { |
||||
break |
||||
} |
||||
} |
||||
|
||||
} else { |
||||
Write-Host "Unable to retrieve list of zig community mirrors from $mirrors_url" |
||||
} |
||||
@ -1,18 +1,18 @@
|
||||
|
||||
#!/bin/sh |
||||
echo `# <#` |
||||
mkdir -p ./zig |
||||
wget https://ziglang.org/download/0.10.1/zig-linux-x86_64-0.10.1.tar.xz -O ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
tar -xf ./zig/zig-linux-x86_64-0.10.1.tar.xz -C ./zig --strip-components=1 |
||||
rm ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
echo "Zig installed." |
||||
./zig/zig version |
||||
exit |
||||
#> > $null |
||||
|
||||
Invoke-WebRequest -Uri "https://ziglang.org/download/0.10.1/zig-windows-x86_64-0.10.1.zip" -OutFile ".\zig-windows-x86_64-0.10.1.zip" |
||||
Expand-Archive -Path ".\zig-windows-x86_64-0.10.1.zip" -DestinationPath ".\" -Force |
||||
Remove-Item -Path " .\zig-windows-x86_64-0.10.1.zip" |
||||
Rename-Item -Path ".\zig-windows-x86_64-0.10.1" -NewName ".\zig" |
||||
Write-Host "Zig installed." |
||||
./zig/zig.exe version |
||||
|
||||
#!/bin/sh |
||||
echo `# <#` |
||||
mkdir -p ./zig |
||||
wget https://ziglang.org/download/0.10.1/zig-linux-x86_64-0.10.1.tar.xz -O ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
tar -xf ./zig/zig-linux-x86_64-0.10.1.tar.xz -C ./zig --strip-components=1 |
||||
rm ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
echo "Zig installed." |
||||
./zig/zig version |
||||
exit |
||||
#> > $null |
||||
|
||||
Invoke-WebRequest -Uri "https://ziglang.org/download/0.10.1/zig-windows-x86_64-0.10.1.zip" -OutFile ".\zig-windows-x86_64-0.10.1.zip" |
||||
Expand-Archive -Path ".\zig-windows-x86_64-0.10.1.zip" -DestinationPath ".\" -Force |
||||
Remove-Item -Path " .\zig-windows-x86_64-0.10.1.zip" |
||||
Rename-Item -Path ".\zig-windows-x86_64-0.10.1" -NewName ".\zig" |
||||
Write-Host "Zig installed." |
||||
./zig/zig.exe version |
||||
@ -1,21 +1,21 @@
|
||||
|
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"getzig.ps1", |
||||
"getzig.bash" |
||||
] |
||||
|
||||
default_outputfile="getzig.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl pwsh powershell bash. |
||||
#nextshellpath entries must be 64 characters or less. |
||||
|
||||
win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c" |
||||
win32.nextshelltype="pwsh" |
||||
win32.outputfile="getzig.cmd" |
||||
|
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"getzig.ps1", |
||||
"getzig.bash" |
||||
] |
||||
|
||||
default_outputfile="getzig.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl pwsh powershell bash. |
||||
#nextshellpath entries must be 64 characters or less. |
||||
|
||||
win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c" |
||||
win32.nextshelltype="pwsh" |
||||
win32.outputfile="getzig.cmd" |
||||
@ -1,176 +1,176 @@
|
||||
|
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/getpunk.cmd' -OutFile 'getpunk.cmd'; Start-Process 'getpunk.cmd' -NoNewWindow -Wait" |
||||
|
||||
#todo - support either fossil or git |
||||
|
||||
#check if git available |
||||
#if not, check/install winget, winget git |
||||
|
||||
$git_upstream = "https://gitea1.intx.com.au/jn/punkshell.git" |
||||
$launchdir = Get-Location #store original CWD |
||||
$scriptfolder = Resolve-Path (Split-Path -Path $PSCommandPath -Parent) |
||||
$punkfolder = "" |
||||
$scriptroot = "$([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath))" |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
|
||||
if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) { |
||||
Write-Host "The git command doesn't seem to be available. Will attempt to install using winget." |
||||
#Find-Module/Install-Module: older mechanism, available in powershell |
||||
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? |
||||
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client |
||||
if (${wgclient}.Length -eq 0) { |
||||
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." |
||||
Install-PackageProvider -Name NuGet -Force |
||||
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy |
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
#Applies to all versions of PowerShell for the user, and is persistent for current user. |
||||
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted |
||||
} |
||||
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery |
||||
Repair-WinGetPackageManager |
||||
import-module -name Microsoft.Winget.client |
||||
|
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted |
||||
} |
||||
} else { |
||||
Write-Host "Microsoft.WinGet.Client is available" |
||||
} |
||||
$gitversion = (Find-WinGetPackage Git.Git).Version |
||||
if ($gitversion) { |
||||
Write-Host "Installing git version: ${gitversion}" |
||||
Install-WinGetPackage -Id "Git.Git" |
||||
} else { |
||||
Write-Host "Failed to find git using winget" |
||||
exit |
||||
} |
||||
#refreshing the current session's path should make the new command available (required for powershell 5 at least) |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
if (Get-Command "git" -ErrorAction SilentlyContinue) { |
||||
Write-Host "git is now available" |
||||
} else { |
||||
Write-Host "git is still not available" |
||||
Write-HOst "Please install Git or relaunch your terminal and check it is available on the path." |
||||
exit |
||||
} |
||||
} |
||||
|
||||
if (($launchdir.Path) -ne ($scriptfolder.Path)) { |
||||
Write-Host "The current directory does not seem to be the folder in which the getpunk script is located." |
||||
$answer = Read-Host "Do you want to use the current directory '$($launchdir.Path) as the location for punkshell? Y|N`n Y to use launchdir '$($launchdir.Path)'`n 'N' to use script folder '$($scriptfolder.Path)`n Any other value to abort: " |
||||
if ($answer -match "y") { |
||||
$punkfolder = $launchdir |
||||
} elseif ($answer -match "n") { |
||||
$punkfolder = $scriptfolder |
||||
} else { |
||||
exit 1 |
||||
} |
||||
|
||||
} else { |
||||
$punkfolder = $scriptfolder |
||||
} |
||||
$punkfoldercontents = Get-ChildItem -Path $punkfolder -Force #include possibly hidden items such as .git folder |
||||
$contentcount = ( $punkfoldercontents | Measure-Object).Count |
||||
$effectively_empty = 0 |
||||
if ($contentcount -eq 0) { |
||||
$effectively_empty = 1 |
||||
} elseif ($punkfolder -eq $scriptfolder -and $contentcount -lt 10) { |
||||
#treat as empty if we have only a few files matching script root name |
||||
$scriptlike = get-childitem -Path $punkfolder | Where-Object {$_.name -like "${scriptroot}.*"} |
||||
if ($scriptlike.Count -eq $contentcount) { |
||||
$effectively_empty = 1 |
||||
} |
||||
} |
||||
if (-not($effectively_empty)) { |
||||
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { |
||||
Write-Host "The folder $punkfolder contains other items, and it does not appear to be a git project root." |
||||
Write-Host "Please place this script in an empty folder which is to be the punkshell base folder." |
||||
exit |
||||
} else { |
||||
$repo_origin = git remote get-url origin |
||||
if ($repo_origin -ne $git_upstream) { |
||||
Write-Host "The current repository origin '$repo_origin' is not the expected upstream '${git_upstream}'" |
||||
$answer = Read-Host "Continue anyway? (Y|N)" |
||||
if (-not($answer -match "y")) { |
||||
exit 1 |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
#punkfolder is empty, or has just the current script |
||||
} |
||||
Set-Location -Path $punkfolder |
||||
|
||||
|
||||
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { |
||||
git init |
||||
git remote add origin $git_upstream |
||||
} |
||||
git fetch origin |
||||
if (($launchdir.Path) -eq ($scriptfolder.Path)) { |
||||
if (Test-Path -Path "${scriptroot}.cmd") { |
||||
#rename-item won't allow overwriting existing target file |
||||
Move-Item -Path "${scriptroot}.cmd" -Destination "${scriptroot}.cmd.lastrun" -Force |
||||
} |
||||
} |
||||
git pull $git_upstream master |
||||
git checkout "${scriptroot}.cmd" |
||||
git branch --set-upstream-to=origin/master master |
||||
|
||||
Set-Location $launchdir #restore original CWD |
||||
#see also: https://github.com/jdhitsolutions/WTToolbox |
||||
|
||||
# Define the necessary Win32 API functions and constants |
||||
Add-Type -TypeDefinition @" |
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
public class WinAPI |
||||
{ |
||||
// Console Input/Output Handles |
||||
public const int STD_OUTPUT_HANDLE = -11; |
||||
public const uint ENABLE_QUICK_EDIT_MODE = 0x0040; |
||||
public const uint ENABLE_EXTENDED_FLAGS = 0x0080; |
||||
public const uint ENABLE_MOUSE_INPUT = 0x0010; |
||||
public const uint ENABLE_WINDOW_INPUT = 0x0008; |
||||
public const uint ENABLE_INSERT_MODE = 0x0020; |
||||
public const uint ENABLE_LINE_INPUT = 0x0002; |
||||
public const uint ENABLE_ECHO_INPUT = 0x0004; |
||||
public const uint ENABLE_PROCESSED_INPUT = 0x0001; |
||||
|
||||
// Console Modes |
||||
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; |
||||
public const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008; |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern IntPtr GetStdHandle(int nStdHandle); |
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); |
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); |
||||
} |
||||
"@ |
||||
|
||||
# Get the handle to the console output buffer |
||||
$stdoutHandle = [WinAPI]::GetStdHandle([WinAPI]::STD_OUTPUT_HANDLE) |
||||
|
||||
# Get the current console mode |
||||
[uint32]$currentMode = 0 |
||||
if (![WinAPI]::GetConsoleMode($stdoutHandle, [ref]$currentMode)) { |
||||
Write-Error "Failed to get console mode. Error code: $($LAST_ERROR)" |
||||
return |
||||
} |
||||
|
||||
# Enable virtual terminal processing |
||||
$newMode = $currentMode -bor [WinAPI]::ENABLE_VIRTUAL_TERMINAL_PROCESSING |
||||
|
||||
# Set the new console mode |
||||
if (-not [WinAPI]::SetConsoleMode($stdoutHandle, $newMode)) { |
||||
Write-Error "Failed to set console mode. Error code: $($LAST_ERROR)" |
||||
return |
||||
} |
||||
|
||||
Write-Host "Virtual terminal processing enabled successfully." |
||||
|
||||
write-host "`e[92m getpunk done `e[m" |
||||
|
||||
#powershell -Command "Invoke-WebRequest -Uri 'https://www.gitea1.intx.com.au/jn/punkshell/raw/branch/master/getpunk.cmd' -OutFile 'getpunk.cmd'; Start-Process 'getpunk.cmd' -NoNewWindow -Wait" |
||||
|
||||
#todo - support either fossil or git |
||||
|
||||
#check if git available |
||||
#if not, check/install winget, winget git |
||||
|
||||
$git_upstream = "https://gitea1.intx.com.au/jn/punkshell.git" |
||||
$launchdir = Get-Location #store original CWD |
||||
$scriptfolder = Resolve-Path (Split-Path -Path $PSCommandPath -Parent) |
||||
$punkfolder = "" |
||||
$scriptroot = "$([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath))" |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
|
||||
if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) { |
||||
Write-Host "The git command doesn't seem to be available. Will attempt to install using winget." |
||||
#Find-Module/Install-Module: older mechanism, available in powershell |
||||
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? |
||||
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client |
||||
if (${wgclient}.Length -eq 0) { |
||||
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." |
||||
Install-PackageProvider -Name NuGet -Force |
||||
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy |
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
#Applies to all versions of PowerShell for the user, and is persistent for current user. |
||||
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted |
||||
} |
||||
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery |
||||
Repair-WinGetPackageManager |
||||
import-module -name Microsoft.Winget.client |
||||
|
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted |
||||
} |
||||
} else { |
||||
Write-Host "Microsoft.WinGet.Client is available" |
||||
} |
||||
$gitversion = (Find-WinGetPackage Git.Git).Version |
||||
if ($gitversion) { |
||||
Write-Host "Installing git version: ${gitversion}" |
||||
Install-WinGetPackage -Id "Git.Git" |
||||
} else { |
||||
Write-Host "Failed to find git using winget" |
||||
exit |
||||
} |
||||
#refreshing the current session's path should make the new command available (required for powershell 5 at least) |
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") |
||||
if (Get-Command "git" -ErrorAction SilentlyContinue) { |
||||
Write-Host "git is now available" |
||||
} else { |
||||
Write-Host "git is still not available" |
||||
Write-HOst "Please install Git or relaunch your terminal and check it is available on the path." |
||||
exit |
||||
} |
||||
} |
||||
|
||||
if (($launchdir.Path) -ne ($scriptfolder.Path)) { |
||||
Write-Host "The current directory does not seem to be the folder in which the getpunk script is located." |
||||
$answer = Read-Host "Do you want to use the current directory '$($launchdir.Path) as the location for punkshell? Y|N`n Y to use launchdir '$($launchdir.Path)'`n 'N' to use script folder '$($scriptfolder.Path)`n Any other value to abort: " |
||||
if ($answer -match "y") { |
||||
$punkfolder = $launchdir |
||||
} elseif ($answer -match "n") { |
||||
$punkfolder = $scriptfolder |
||||
} else { |
||||
exit 1 |
||||
} |
||||
|
||||
} else { |
||||
$punkfolder = $scriptfolder |
||||
} |
||||
$punkfoldercontents = Get-ChildItem -Path $punkfolder -Force #include possibly hidden items such as .git folder |
||||
$contentcount = ( $punkfoldercontents | Measure-Object).Count |
||||
$effectively_empty = 0 |
||||
if ($contentcount -eq 0) { |
||||
$effectively_empty = 1 |
||||
} elseif ($punkfolder -eq $scriptfolder -and $contentcount -lt 10) { |
||||
#treat as empty if we have only a few files matching script root name |
||||
$scriptlike = get-childitem -Path $punkfolder | Where-Object {$_.name -like "${scriptroot}.*"} |
||||
if ($scriptlike.Count -eq $contentcount) { |
||||
$effectively_empty = 1 |
||||
} |
||||
} |
||||
if (-not($effectively_empty)) { |
||||
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { |
||||
Write-Host "The folder $punkfolder contains other items, and it does not appear to be a git project root." |
||||
Write-Host "Please place this script in an empty folder which is to be the punkshell base folder." |
||||
exit |
||||
} else { |
||||
$repo_origin = git remote get-url origin |
||||
if ($repo_origin -ne $git_upstream) { |
||||
Write-Host "The current repository origin '$repo_origin' is not the expected upstream '${git_upstream}'" |
||||
$answer = Read-Host "Continue anyway? (Y|N)" |
||||
if (-not($answer -match "y")) { |
||||
exit 1 |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
#punkfolder is empty, or has just the current script |
||||
} |
||||
Set-Location -Path $punkfolder |
||||
|
||||
|
||||
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { |
||||
git init |
||||
git remote add origin $git_upstream |
||||
} |
||||
git fetch origin |
||||
if (($launchdir.Path) -eq ($scriptfolder.Path)) { |
||||
if (Test-Path -Path "${scriptroot}.cmd") { |
||||
#Rename-Item won't allow overwriting existing target file |
||||
Move-Item -Path "${scriptroot}.cmd" -Destination "${scriptroot}.cmd.lastrun" -Force |
||||
} |
||||
} |
||||
git pull $git_upstream master |
||||
git checkout "${scriptroot}.cmd" |
||||
git branch --set-upstream-to=origin/master master |
||||
|
||||
Set-Location $launchdir #restore original CWD |
||||
#see also: https://github.com/jdhitsolutions/WTToolbox |
||||
|
||||
# Define the necessary Win32 API functions and constants |
||||
Add-Type -TypeDefinition @" |
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
public class WinAPI |
||||
{ |
||||
// Console Input/Output Handles |
||||
public const int STD_OUTPUT_HANDLE = -11; |
||||
public const uint ENABLE_QUICK_EDIT_MODE = 0x0040; |
||||
public const uint ENABLE_EXTENDED_FLAGS = 0x0080; |
||||
public const uint ENABLE_MOUSE_INPUT = 0x0010; |
||||
public const uint ENABLE_WINDOW_INPUT = 0x0008; |
||||
public const uint ENABLE_INSERT_MODE = 0x0020; |
||||
public const uint ENABLE_LINE_INPUT = 0x0002; |
||||
public const uint ENABLE_ECHO_INPUT = 0x0004; |
||||
public const uint ENABLE_PROCESSED_INPUT = 0x0001; |
||||
|
||||
// Console Modes |
||||
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; |
||||
public const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008; |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern IntPtr GetStdHandle(int nStdHandle); |
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); |
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); |
||||
} |
||||
"@ |
||||
|
||||
# Get the handle to the console output buffer |
||||
$stdoutHandle = [WinAPI]::GetStdHandle([WinAPI]::STD_OUTPUT_HANDLE) |
||||
|
||||
# Get the current console mode |
||||
[uint32]$currentMode = 0 |
||||
if (![WinAPI]::GetConsoleMode($stdoutHandle, [ref]$currentMode)) { |
||||
Write-Error "Failed to get console mode. Error code: $($LAST_ERROR)" |
||||
return |
||||
} |
||||
|
||||
# Enable virtual terminal processing |
||||
$newMode = $currentMode -bor [WinAPI]::ENABLE_VIRTUAL_TERMINAL_PROCESSING |
||||
|
||||
# Set the new console mode |
||||
if (-not [WinAPI]::SetConsoleMode($stdoutHandle, $newMode)) { |
||||
Write-Error "Failed to set console mode. Error code: $($LAST_ERROR)" |
||||
return |
||||
} |
||||
|
||||
Write-Host "Virtual terminal processing enabled successfully." |
||||
|
||||
write-host "`e[92m getpunk done `e[m" |
||||
|
||||
@ -1,23 +1,23 @@
|
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"getpunk.ps1", |
||||
"getpunk.bash" |
||||
] |
||||
|
||||
default_outputfile="getpunk.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl powershell bash. |
||||
#nextshellpath entries must be 128 characters or less. |
||||
|
||||
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" |
||||
#win32.nextshelltype="pwsh" |
||||
|
||||
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy ByPass -File" |
||||
win32.nextshelltype="powershell" |
||||
win32.outputfile="getpunk.cmd" |
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"getpunk.ps1", |
||||
"getpunk.bash" |
||||
] |
||||
|
||||
default_outputfile="getpunk.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl powershell bash. |
||||
#nextshellpath entries must be 128 characters or less. |
||||
|
||||
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" |
||||
#win32.nextshelltype="pwsh" |
||||
|
||||
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy ByPass -File" |
||||
win32.nextshelltype="powershell" |
||||
win32.outputfile="getpunk.cmd" |
||||
|
||||
@ -1,416 +1,416 @@
|
||||
|
||||
|
||||
function GetDynamicParamDictionary { |
||||
[CmdletBinding()] |
||||
param( |
||||
[Parameter(ValueFromPipeline=$true, Mandatory=$true)] |
||||
[string] $CommandName |
||||
) |
||||
|
||||
begin { |
||||
# Get a list of params that should be ignored (they're common to all advanced functions) |
||||
$CommonParameterNames = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([type] [System.Management.Automation.Internal.CommonParameters]) | |
||||
Get-Member -MemberType Properties | |
||||
Select-Object -ExpandProperty Name |
||||
} |
||||
|
||||
process { |
||||
# Create the dictionary that this scriptblock will return: |
||||
$DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary |
||||
|
||||
# Convert to object array and get rid of Common params: |
||||
(Get-Command $CommandName | Select-Object -exp Parameters).GetEnumerator() | |
||||
Where-Object { $CommonParameterNames -notcontains $_.Key } | |
||||
ForEach-Object { |
||||
$DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter ( |
||||
$_.Key, |
||||
$_.Value.ParameterType, |
||||
$_.Value.Attributes |
||||
) |
||||
$DynParamDictionary.Add($_.Key, $DynamicParameter) |
||||
} |
||||
|
||||
# Return the dynamic parameters |
||||
return $DynParamDictionary |
||||
} |
||||
} |
||||
function ParameterDefinitions { |
||||
param( |
||||
[Parameter(ValueFromRemainingArguments=$true,Position = 1)][string[]] $opts |
||||
) |
||||
} |
||||
|
||||
function psmain { |
||||
[CmdletBinding()] |
||||
#Empty param block (extra params can be added) |
||||
param( |
||||
[Parameter(Mandatory=$false, Position = 0)][string] $action = "" |
||||
) |
||||
dynamicparam { |
||||
if ($action -eq 'list') { |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "listruntime" |
||||
Mandatory = $false |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'remote', [switch], $attributeCollection |
||||
) |
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('remote', $dynParam1) |
||||
return $paramDictionary |
||||
} elseif ($action -eq 'fetch') { |
||||
#GetDynamicParamDictionary ParameterDefinitions |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "fetchruntime" |
||||
Mandatory = $false |
||||
Position = 1 |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'runtime', [string], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('runtime', $dynParam1) |
||||
return $paramDictionary |
||||
} elseif ($action -eq 'run') { |
||||
#GetDynamicParamDictionary ParameterDefinitions |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "runargs" |
||||
Mandatory = $false |
||||
ValueFromRemainingArguments = $true |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'opts', [string[]], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('opts', $dynParam1) |
||||
return $paramDictionary |
||||
} else { |
||||
#accept all args when action is unrecognised - so we can go to help anyway |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "invalidaction" |
||||
Mandatory = $false |
||||
ValueFromRemainingArguments = $true |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'opts', [string[]], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('opts', $dynParam1) |
||||
return $paramDictionary |
||||
} |
||||
} |
||||
process { |
||||
#Called once - we get a single item being our PSBoundParameters dictionary |
||||
#write-host "Bound Parameters:$($PSBoundParameters.Keys)" |
||||
switch ($PSBoundParameters.keys) { |
||||
'action' { |
||||
write-host "got action " $PSBoundParameters.action |
||||
Set-Variable -Name $_ -Value $PSBoundParameters."$_" |
||||
$known_actions = @("fetch", "list", "run") |
||||
if (-not($known_actions -contains $action)) { |
||||
write-host "fetch '$action' not understood. Known_actions: $known_actions" |
||||
exit 1 |
||||
} |
||||
} |
||||
'opts' { |
||||
# write-warning "Unused parameters: $($PSBoundParameters.$_)" |
||||
} |
||||
Default { |
||||
# write-warning "Unhandled parameter -> [$($_)]" |
||||
} |
||||
} |
||||
#foreach ($boundparam in $PSBoundParameters.Keys) { |
||||
# write-host "k: $boundparam" |
||||
#} |
||||
} |
||||
end { |
||||
# PSBoundParameters |
||||
#write-host "action:'$action'" |
||||
$outbase = $PSScriptRoot |
||||
$outbase = Resolve-Path -Path $outbase |
||||
#expected script location is the bin folder of a punk project |
||||
$rtfolder = Join-Path -Path $outbase -ChildPath "runtime" |
||||
#Binary artifact server url. (git is not ideal for this - but will do for now - todo - use artifact system within gitea?) |
||||
$artifacturl = "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master" |
||||
switch ($action) { |
||||
'fetch' { |
||||
$arch = "win32-x86_64" |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
$archurl = "$artifacturl/$arch" |
||||
$sha1url = "$archurl/sha1sums.txt" |
||||
$runtime = "tclsh902z.exe" |
||||
foreach ($boundparam in $PSBoundParameters.Keys) { |
||||
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])" |
||||
} |
||||
if ( $PSBoundParameters["runtime"].Length ) { |
||||
$runtime = $PSBoundParameters["runtime"] |
||||
} |
||||
$fileurl = "$archurl/$runtime" |
||||
|
||||
$output = join-path -Path $archfolder -ChildPath $runtime |
||||
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" |
||||
|
||||
$container = split-path -Path $output -Parent |
||||
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present |
||||
|
||||
try { |
||||
Write-Host "Fetching $sha1url" |
||||
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop |
||||
Write-Host "sha1 saved at $sha1local" |
||||
} catch { |
||||
Write-Host "An error occurred while downloading ${sha1url}: $($_.Exception.Message)" |
||||
if ($_.Exception.Response) { |
||||
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" |
||||
} |
||||
} |
||||
if (Test-Path -Path $sha1local -PathType Leaf) { |
||||
$sha1Content = Get-Content -Path $sha1local |
||||
$stored_sha1 = "" |
||||
foreach ($line in $sha1Content) { |
||||
#all sha1sums have * (binary indicator) - review |
||||
$match = [regex]::Match($line,"(.*) [*]${runtime}$") |
||||
if ($match.Success) { |
||||
$stored_sha1 = $match.Groups[1].Value |
||||
Write-host "stored hash from sha1sums.txt: $storedhash" |
||||
break |
||||
} |
||||
} |
||||
if ($stored_sha1 -eq "") { |
||||
Write-Host "Unable to locate hash for $runtime in $sha1local - Aborting" |
||||
Write-Host "Please download and verify manually" |
||||
return |
||||
} |
||||
|
||||
$need_download = $false |
||||
if (Test-Path -Path $output -PathType Leaf) { |
||||
Write-Host "Runtime already found at $output" |
||||
Write-Host "Checking sha1 checksum of local file versus sha1 of server file" |
||||
$file_sha1 = Get-FileHash -Path "$output" -Algorithm SHA1 |
||||
if (${file_sha1}.Hash -ne $stored_sha1) { |
||||
Write-Host "$runtime on server has different sha1 hash - Download required" |
||||
$need_download = $true |
||||
} |
||||
} else { |
||||
Write-Host "$runtime not found locally - Download required" |
||||
$need_download = $true |
||||
} |
||||
|
||||
if ($need_download) { |
||||
Write-Host "Downloading from $fileurl ..." |
||||
try { |
||||
Invoke-WebRequest -Uri $fileurl -OutFile "${output}.tmp" -ErrorAction Stop |
||||
Write-Host "Runtime saved at $output.tmp" |
||||
} |
||||
catch { |
||||
Write-Host "An error occurred while downloading $fileurl $($_.Exception.Message)" |
||||
if ($_.Exception.Response) { |
||||
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" |
||||
} |
||||
return |
||||
} |
||||
Write-Host "comparing sha1 checksum of downloaded file with data in sha1sums.txt" |
||||
Start-Sleep -Seconds 1 #REVIEW - give at least some time for windows to do its thing? (av filters?) |
||||
$newfile_sha1 = Get-FileHash -Path "${output}.tmp" -Algorithm SHA1 |
||||
if (${newfile_sha1}.Hash -eq $stored_sha1) { |
||||
Write-Host "sha1 checksum ok" |
||||
Move-Item -Path "${output}.tmp" -Destination "${output}" -Force |
||||
Write-Host "Runtime is available at ${output}" |
||||
} else { |
||||
Write-Host "WARNING! sha1 of downloaded file at $output.tmp does not match stored sha1 from sha1sums.txt" |
||||
return |
||||
} |
||||
} else { |
||||
Write-Host "Local copy of runtime at $output seems to match sha1 checksum of file on server." |
||||
Write-Host "No download required" |
||||
} |
||||
} else { |
||||
Write-Host "Unable to consult local copy of sha1sums.txt at $sha1local" |
||||
if (Test-Path -Path $output -PathType Leaf) { |
||||
Write-Host "A runtime is available at $output - but we failed to retrieve the list of sha1sums from the server" |
||||
Write-Host "Unable to check for updated version at this time." |
||||
} else { |
||||
Write-Host "Please retry - or manually download a runtime from $archurl and verify checksums" |
||||
} |
||||
} |
||||
} |
||||
'run' { |
||||
#select first (or configured default) runtime and launch, passing arguments |
||||
$arch = "win32-x86_64" |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
if (-not(Test-Path -Path $archfolder -PathType Container)) { |
||||
write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install" |
||||
} else { |
||||
$dircontents = (get-childItem -Path $archfolder -File | Sort-Object Name) |
||||
if ($dircontents.Count -gt 0) { |
||||
#write-host "run.." |
||||
write-host "num params: $($PSBoundParameters.opts.count)" |
||||
|
||||
#todo - use 'active' runtime - need to lookup (PSToml?) |
||||
#when no 'active' runtime for this os-arch - use last item (sorted in dictionary order) |
||||
$active = $dircontents[-1].FullName |
||||
write-host "using: $active" |
||||
if ($PSBoundParameters.opts.Length -gt 0) { |
||||
$optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null |
||||
write-host "type of opts: $($optsType.FullName)" |
||||
foreach ($boundparam in $PSBoundParameters.opts) { |
||||
write-host $boundparam |
||||
} |
||||
Write-Host "opts: $($PSBoundParameters.opts)" |
||||
Write-Host "args: $args" |
||||
Write-HOst "argscount: $($args.Count)" |
||||
$arglist = @() |
||||
foreach ($o in $PSBoundParameters.opts) { |
||||
$oquoted = $o -replace '"', "`\`"" |
||||
#$oquoted = $oquoted -replace "'", "`'" |
||||
if ($oquoted -match "\s") { |
||||
$oquoted = "`"$oquoted`"" |
||||
} |
||||
$arglist += @($oquoted) |
||||
} |
||||
$arglist = $arglist.TrimEnd(' ') |
||||
write-host "arglist: $arglist" |
||||
#$arglist = $PSBoundParameters.opts |
||||
Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait |
||||
} else { |
||||
#powershell 5.1 and earlier can't accept an empty -ArgumentList value :/ !! |
||||
#$arglist = @() |
||||
#Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait |
||||
#Start-Process -FilePath $active -ArgumentList "" -NoNewWindow -Wait |
||||
Start-Process -FilePath $active -NoNewWindow -Wait |
||||
} |
||||
} else { |
||||
write-host "No files found in $archfolder" |
||||
write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install." |
||||
} |
||||
} |
||||
} |
||||
'list' { |
||||
#todo - option to list for other os-arch |
||||
$arch = 'win32-x86_64' |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" |
||||
$archurl = "$artifacturl/$arch" |
||||
$sha1url = "$archurl/sha1sums.txt" |
||||
if ( $PSBoundParameters.ContainsKey('remote') ) { |
||||
if (-not (test-path -Path $archfolder -Type Container)) { |
||||
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present |
||||
} |
||||
write-host "Checking for available remote runtimes for" |
||||
Write-Host "Fetching $sha1url" |
||||
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop |
||||
Write-Host "sha1 saved at $sha1local" |
||||
$sha1Content = Get-Content -Path $sha1local |
||||
$remotedict = @{} |
||||
foreach ($line in $sha1Content) { |
||||
#all sha1sums have * (binary indicator) - review |
||||
$match = [regex]::Match($line,"(.*) [*](.*)$") |
||||
if ($match.Success) { |
||||
$server_sha1 = $match.Groups[1].Value |
||||
$server_rt = $match.Groups[2].Value |
||||
$remotedict[$server_rt] = $server_sha1 |
||||
} |
||||
} |
||||
|
||||
$localdict = @{} |
||||
if (test-path -Path $archfolder -Type Container) { |
||||
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) |
||||
foreach ($f in $dircontents) { |
||||
$local_sha1 = Get-FileHash -Path $(${f}.FullName) -Algorithm SHA1 |
||||
$localdict[$f.Name] = ${local_sha1}.Hash |
||||
} |
||||
} |
||||
|
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Runtimes for $arch" |
||||
Write-host "Local $archfolder" |
||||
Write-host "Remote $archurl" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Local Remote" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
# 12345678910234567892023456789302345 |
||||
$G = "`e[32m" #Green |
||||
$Y = "`e[33m" #Yellow |
||||
$R = "`e[31m" #Red |
||||
$RST = "`e[m" |
||||
foreach ($key in $localdict.Keys) { |
||||
$local_sha1 = $($localdict[$key]) |
||||
if ($remotedict.ContainsKey($key)) { |
||||
if ($local_sha1 -eq $remotedict[$key]) { |
||||
$rhs = "Same version" |
||||
$C = $G |
||||
} else { |
||||
$rhs = "UPDATE AVAILABLE" |
||||
$C = $Y |
||||
} |
||||
} else { |
||||
$C = $R |
||||
$rhs = "(not listed on server)" |
||||
} |
||||
#ansi problems from cmd.exe not in windows terminal - review |
||||
$C = "" |
||||
$RST = "" |
||||
$lhs = "$key".PadRight(35, ' ') |
||||
write-host -nonewline "${C}${lhs}${RST}" |
||||
write-host $rhs |
||||
} |
||||
$lhs_missing = "-".PadRight(35, ' ') |
||||
foreach ($key in $remotedict.Keys) { |
||||
if (-not ($localdict.ContainsKey($key))) { |
||||
write-host -nonewline $lhs_missing |
||||
write-host $key |
||||
} |
||||
} |
||||
Write-host "-----------------------------------------------------------------------" |
||||
|
||||
} else { |
||||
if (test-path -Path $archfolder -Type Container) { |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-Host "Local runtimes for $arch" |
||||
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) |
||||
write-host "$(${dircontents}.count) files in $archfolder" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
foreach ($f in $dircontents) { |
||||
write-host $f.Name |
||||
} |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Use: 'list -remote' to compare local runtimes with those available on the artifact server" |
||||
} else { |
||||
write-host "No runtimes seem to be installed for $arch in $archfolder`nPlease use 'runtime.cmd fetch' to install." |
||||
write-host "Use 'runtime.cmd list -remote' to see available runtimes for $arch" |
||||
} |
||||
} |
||||
} |
||||
default { |
||||
$actions = @("fetch", "list", "run") |
||||
write-host "Available actions: $actions" |
||||
write-host "received" |
||||
foreach ($boundparam in $PSBoundParameters.opts) { |
||||
write-host $boundparam |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $PSBoundParameters |
||||
} |
||||
} |
||||
#write-host (psmain @args) |
||||
#$returnvalue = psmain @args |
||||
#Write-Host "Function Returned $returnvalue" -ForegroundColor Cyan |
||||
#return $returnvalue |
||||
psmain @args | out-null |
||||
exit 0 |
||||
|
||||
|
||||
|
||||
function GetDynamicParamDictionary { |
||||
[CmdletBinding()] |
||||
param( |
||||
[Parameter(ValueFromPipeline=$true, Mandatory=$true)] |
||||
[string] $CommandName |
||||
) |
||||
|
||||
begin { |
||||
# Get a list of params that should be ignored (they're common to all advanced functions) |
||||
$CommonParameterNames = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([type] [System.Management.Automation.Internal.CommonParameters]) | |
||||
Get-Member -MemberType Properties | |
||||
Select-Object -ExpandProperty Name |
||||
} |
||||
|
||||
process { |
||||
# Create the dictionary that this scriptblock will return: |
||||
$DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary |
||||
|
||||
# Convert to object array and get rid of Common params: |
||||
(Get-Command $CommandName | Select-Object -exp Parameters).GetEnumerator() | |
||||
Where-Object { $CommonParameterNames -notcontains $_.Key } | |
||||
ForEach-Object { |
||||
$DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter ( |
||||
$_.Key, |
||||
$_.Value.ParameterType, |
||||
$_.Value.Attributes |
||||
) |
||||
$DynParamDictionary.Add($_.Key, $DynamicParameter) |
||||
} |
||||
|
||||
# Return the dynamic parameters |
||||
return $DynParamDictionary |
||||
} |
||||
} |
||||
function ParameterDefinitions { |
||||
param( |
||||
[Parameter(ValueFromRemainingArguments=$true,Position = 1)][string[]] $opts |
||||
) |
||||
} |
||||
|
||||
function psmain { |
||||
[CmdletBinding()] |
||||
#Empty param block (extra params can be added) |
||||
param( |
||||
[Parameter(Mandatory=$false, Position = 0)][string] $action = "" |
||||
) |
||||
dynamicparam { |
||||
if ($action -eq 'list') { |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "listruntime" |
||||
Mandatory = $false |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'remote', [switch], $attributeCollection |
||||
) |
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('remote', $dynParam1) |
||||
return $paramDictionary |
||||
} elseif ($action -eq 'fetch') { |
||||
#GetDynamicParamDictionary ParameterDefinitions |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "fetchruntime" |
||||
Mandatory = $false |
||||
Position = 1 |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'runtime', [string], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('runtime', $dynParam1) |
||||
return $paramDictionary |
||||
} elseif ($action -eq 'run') { |
||||
#GetDynamicParamDictionary ParameterDefinitions |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "runargs" |
||||
Mandatory = $false |
||||
ValueFromRemainingArguments = $true |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'opts', [string[]], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('opts', $dynParam1) |
||||
return $paramDictionary |
||||
} else { |
||||
#accept all args when action is unrecognised - so we can go to help anyway |
||||
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ |
||||
ParameterSetName = "invalidaction" |
||||
Mandatory = $false |
||||
ValueFromRemainingArguments = $true |
||||
} |
||||
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() |
||||
$attributeCollection.Add($parameterAttribute) |
||||
|
||||
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( |
||||
'opts', [string[]], $attributeCollection |
||||
) |
||||
|
||||
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() |
||||
$paramDictionary.Add('opts', $dynParam1) |
||||
return $paramDictionary |
||||
} |
||||
} |
||||
process { |
||||
#Called once - we get a single item being our PSBoundParameters dictionary |
||||
#write-host "Bound Parameters:$($PSBoundParameters.Keys)" |
||||
switch ($PSBoundParameters.keys) { |
||||
'action' { |
||||
write-host "got action " $PSBoundParameters.action |
||||
Set-Variable -Name $_ -Value $PSBoundParameters."$_" |
||||
$known_actions = @("fetch", "list", "run") |
||||
if (-not($known_actions -contains $action)) { |
||||
write-host "fetch '$action' not understood. Known_actions: $known_actions" |
||||
exit 1 |
||||
} |
||||
} |
||||
'opts' { |
||||
# write-warning "Unused parameters: $($PSBoundParameters.$_)" |
||||
} |
||||
Default { |
||||
# write-warning "Unhandled parameter -> [$($_)]" |
||||
} |
||||
} |
||||
#foreach ($boundparam in $PSBoundParameters.Keys) { |
||||
# write-host "k: $boundparam" |
||||
#} |
||||
} |
||||
end { |
||||
# PSBoundParameters |
||||
#write-host "action:'$action'" |
||||
$outbase = $PSScriptRoot |
||||
$outbase = Resolve-Path -Path $outbase |
||||
#expected script location is the bin folder of a punk project |
||||
$rtfolder = Join-Path -Path $outbase -ChildPath "runtime" |
||||
#Binary artifact server url. (git is not ideal for this - but will do for now - todo - use artifact system within gitea?) |
||||
$artifacturl = "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master" |
||||
switch ($action) { |
||||
'fetch' { |
||||
$arch = "win32-x86_64" |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
$archurl = "$artifacturl/$arch" |
||||
$sha1url = "$archurl/sha1sums.txt" |
||||
$runtime = "tclsh902z.exe" |
||||
foreach ($boundparam in $PSBoundParameters.Keys) { |
||||
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])" |
||||
} |
||||
if ( $PSBoundParameters["runtime"].Length ) { |
||||
$runtime = $PSBoundParameters["runtime"] |
||||
} |
||||
$fileurl = "$archurl/$runtime" |
||||
|
||||
$output = join-path -Path $archfolder -ChildPath $runtime |
||||
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" |
||||
|
||||
$container = split-path -Path $output -Parent |
||||
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present |
||||
|
||||
try { |
||||
Write-Host "Fetching $sha1url" |
||||
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop |
||||
Write-Host "sha1 saved at $sha1local" |
||||
} catch { |
||||
Write-Host "An error occurred while downloading ${sha1url}: $($_.Exception.Message)" |
||||
if ($_.Exception.Response) { |
||||
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" |
||||
} |
||||
} |
||||
if (Test-Path -Path $sha1local -PathType Leaf) { |
||||
$sha1Content = Get-Content -Path $sha1local |
||||
$stored_sha1 = "" |
||||
foreach ($line in $sha1Content) { |
||||
#all sha1sums have * (binary indicator) - review |
||||
$match = [regex]::Match($line,"(.*) [*]${runtime}$") |
||||
if ($match.Success) { |
||||
$stored_sha1 = $match.Groups[1].Value |
||||
Write-host "stored hash from sha1sums.txt: $storedhash" |
||||
break |
||||
} |
||||
} |
||||
if ($stored_sha1 -eq "") { |
||||
Write-Host "Unable to locate hash for $runtime in $sha1local - Aborting" |
||||
Write-Host "Please download and verify manually" |
||||
return |
||||
} |
||||
|
||||
$need_download = $false |
||||
if (Test-Path -Path $output -PathType Leaf) { |
||||
Write-Host "Runtime already found at $output" |
||||
Write-Host "Checking sha1 checksum of local file versus sha1 of server file" |
||||
$file_sha1 = Get-FileHash -Path "$output" -Algorithm SHA1 |
||||
if (${file_sha1}.Hash -ne $stored_sha1) { |
||||
Write-Host "$runtime on server has different sha1 hash - Download required" |
||||
$need_download = $true |
||||
} |
||||
} else { |
||||
Write-Host "$runtime not found locally - Download required" |
||||
$need_download = $true |
||||
} |
||||
|
||||
if ($need_download) { |
||||
Write-Host "Downloading from $fileurl ..." |
||||
try { |
||||
Invoke-WebRequest -Uri $fileurl -OutFile "${output}.tmp" -ErrorAction Stop |
||||
Write-Host "Runtime saved at $output.tmp" |
||||
} |
||||
catch { |
||||
Write-Host "An error occurred while downloading $fileurl $($_.Exception.Message)" |
||||
if ($_.Exception.Response) { |
||||
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" |
||||
} |
||||
return |
||||
} |
||||
Write-Host "comparing sha1 checksum of downloaded file with data in sha1sums.txt" |
||||
Start-Sleep -Seconds 1 #REVIEW - give at least some time for windows to do its thing? (av filters?) |
||||
$newfile_sha1 = Get-FileHash -Path "${output}.tmp" -Algorithm SHA1 |
||||
if (${newfile_sha1}.Hash -eq $stored_sha1) { |
||||
Write-Host "sha1 checksum ok" |
||||
Move-Item -Path "${output}.tmp" -Destination "${output}" -Force |
||||
Write-Host "Runtime is available at ${output}" |
||||
} else { |
||||
Write-Host "WARNING! sha1 of downloaded file at $output.tmp does not match stored sha1 from sha1sums.txt" |
||||
return |
||||
} |
||||
} else { |
||||
Write-Host "Local copy of runtime at $output seems to match sha1 checksum of file on server." |
||||
Write-Host "No download required" |
||||
} |
||||
} else { |
||||
Write-Host "Unable to consult local copy of sha1sums.txt at $sha1local" |
||||
if (Test-Path -Path $output -PathType Leaf) { |
||||
Write-Host "A runtime is available at $output - but we failed to retrieve the list of sha1sums from the server" |
||||
Write-Host "Unable to check for updated version at this time." |
||||
} else { |
||||
Write-Host "Please retry - or manually download a runtime from $archurl and verify checksums" |
||||
} |
||||
} |
||||
} |
||||
'run' { |
||||
#select first (or configured default) runtime and launch, passing arguments |
||||
$arch = "win32-x86_64" |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
if (-not(Test-Path -Path $archfolder -PathType Container)) { |
||||
write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install" |
||||
} else { |
||||
$dircontents = (get-childItem -Path $archfolder -File | Sort-Object Name) |
||||
if ($dircontents.Count -gt 0) { |
||||
#write-host "run.." |
||||
write-host "num params: $($PSBoundParameters.opts.count)" |
||||
|
||||
#todo - use 'active' runtime - need to lookup (PSToml?) |
||||
#when no 'active' runtime for this os-arch - use last item (sorted in dictionary order) |
||||
$active = $dircontents[-1].FullName |
||||
write-host "using: $active" |
||||
if ($PSBoundParameters.opts.Length -gt 0) { |
||||
$optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null |
||||
write-host "type of opts: $($optsType.FullName)" |
||||
foreach ($boundparam in $PSBoundParameters.opts) { |
||||
write-host $boundparam |
||||
} |
||||
Write-Host "opts: $($PSBoundParameters.opts)" |
||||
Write-Host "args: $args" |
||||
Write-HOst "argscount: $($args.Count)" |
||||
$arglist = @() |
||||
foreach ($o in $PSBoundParameters.opts) { |
||||
$oquoted = $o -replace '"', "`\`"" |
||||
#$oquoted = $oquoted -replace "'", "`'" |
||||
if ($oquoted -match "\s") { |
||||
$oquoted = "`"$oquoted`"" |
||||
} |
||||
$arglist += @($oquoted) |
||||
} |
||||
$arglist = $arglist.TrimEnd(' ') |
||||
write-host "arglist: $arglist" |
||||
#$arglist = $PSBoundParameters.opts |
||||
Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait |
||||
} else { |
||||
#powershell 5.1 and earlier can't accept an empty -ArgumentList value :/ !! |
||||
#$arglist = @() |
||||
#Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait |
||||
#Start-Process -FilePath $active -ArgumentList "" -NoNewWindow -Wait |
||||
Start-Process -FilePath $active -NoNewWindow -Wait |
||||
} |
||||
} else { |
||||
write-host "No files found in $archfolder" |
||||
write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install." |
||||
} |
||||
} |
||||
} |
||||
'list' { |
||||
#todo - option to list for other os-arch |
||||
$arch = 'win32-x86_64' |
||||
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" |
||||
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" |
||||
$archurl = "$artifacturl/$arch" |
||||
$sha1url = "$archurl/sha1sums.txt" |
||||
if ( $PSBoundParameters.ContainsKey('remote') ) { |
||||
if (-not (test-path -Path $archfolder -Type Container)) { |
||||
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present |
||||
} |
||||
write-host "Checking for available remote runtimes for" |
||||
Write-Host "Fetching $sha1url" |
||||
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop |
||||
Write-Host "sha1 saved at $sha1local" |
||||
$sha1Content = Get-Content -Path $sha1local |
||||
$remotedict = @{} |
||||
foreach ($line in $sha1Content) { |
||||
#all sha1sums have * (binary indicator) - review |
||||
$match = [regex]::Match($line,"(.*) [*](.*)$") |
||||
if ($match.Success) { |
||||
$server_sha1 = $match.Groups[1].Value |
||||
$server_rt = $match.Groups[2].Value |
||||
$remotedict[$server_rt] = $server_sha1 |
||||
} |
||||
} |
||||
|
||||
$localdict = @{} |
||||
if (test-path -Path $archfolder -Type Container) { |
||||
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) |
||||
foreach ($f in $dircontents) { |
||||
$local_sha1 = Get-FileHash -Path $(${f}.FullName) -Algorithm SHA1 |
||||
$localdict[$f.Name] = ${local_sha1}.Hash |
||||
} |
||||
} |
||||
|
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Runtimes for $arch" |
||||
Write-host "Local $archfolder" |
||||
Write-host "Remote $archurl" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Local Remote" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
# 12345678910234567892023456789302345 |
||||
$G = "`e[32m" #Green |
||||
$Y = "`e[33m" #Yellow |
||||
$R = "`e[31m" #Red |
||||
$RST = "`e[m" |
||||
foreach ($key in $localdict.Keys) { |
||||
$local_sha1 = $($localdict[$key]) |
||||
if ($remotedict.ContainsKey($key)) { |
||||
if ($local_sha1 -eq $remotedict[$key]) { |
||||
$rhs = "Same version" |
||||
$C = $G |
||||
} else { |
||||
$rhs = "UPDATE AVAILABLE" |
||||
$C = $Y |
||||
} |
||||
} else { |
||||
$C = $R |
||||
$rhs = "(not listed on server)" |
||||
} |
||||
#ansi problems from cmd.exe not in windows terminal - review |
||||
$C = "" |
||||
$RST = "" |
||||
$lhs = "$key".PadRight(35, ' ') |
||||
write-host -nonewline "${C}${lhs}${RST}" |
||||
write-host $rhs |
||||
} |
||||
$lhs_missing = "-".PadRight(35, ' ') |
||||
foreach ($key in $remotedict.Keys) { |
||||
if (-not ($localdict.ContainsKey($key))) { |
||||
write-host -nonewline $lhs_missing |
||||
write-host $key |
||||
} |
||||
} |
||||
Write-host "-----------------------------------------------------------------------" |
||||
|
||||
} else { |
||||
if (test-path -Path $archfolder -Type Container) { |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-Host "Local runtimes for $arch" |
||||
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) |
||||
write-host "$(${dircontents}.count) files in $archfolder" |
||||
Write-host "-----------------------------------------------------------------------" |
||||
foreach ($f in $dircontents) { |
||||
write-host $f.Name |
||||
} |
||||
Write-host "-----------------------------------------------------------------------" |
||||
Write-host "Use: 'list -remote' to compare local runtimes with those available on the artifact server" |
||||
} else { |
||||
write-host "No runtimes seem to be installed for $arch in $archfolder`nPlease use 'runtime.cmd fetch' to install." |
||||
write-host "Use 'runtime.cmd list -remote' to see available runtimes for $arch" |
||||
} |
||||
} |
||||
} |
||||
default { |
||||
$actions = @("fetch", "list", "run") |
||||
write-host "Available actions: $actions" |
||||
write-host "received" |
||||
foreach ($boundparam in $PSBoundParameters.opts) { |
||||
write-host $boundparam |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $PSBoundParameters |
||||
} |
||||
} |
||||
#write-host (psmain @args) |
||||
#$returnvalue = psmain @args |
||||
#Write-Host "Function Returned $returnvalue" -ForegroundColor Cyan |
||||
#return $returnvalue |
||||
psmain @args | out-null |
||||
exit 0 |
||||
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"runtime.ps1", |
||||
"runtime.bash" |
||||
] |
||||
|
||||
default_outputfile="runtime.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl powershell bash. |
||||
#nextshellpath entries must be 64 characters or less. |
||||
|
||||
#don't use -c for launching - or in old powershell, arguments such as "a b" will become 2 arguments a b |
||||
#do use -File (even though pwsh doesn't require it) |
||||
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" |
||||
#win32.nextshelltype="pwsh" |
||||
|
||||
#powershell needs cmd.exe to preserve spaced args |
||||
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File" |
||||
win32.nextshelltype="powershell" |
||||
|
||||
win32.outputfile="runtime.cmd" |
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"runtime.ps1", |
||||
"runtime.bash" |
||||
] |
||||
|
||||
default_outputfile="runtime.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl powershell bash. |
||||
#nextshellpath entries must be 64 characters or less. |
||||
|
||||
#don't use -c for launching - or in old powershell, arguments such as "a b" will become 2 arguments a b |
||||
#do use -File (even though pwsh doesn't require it) |
||||
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" |
||||
#win32.nextshelltype="pwsh" |
||||
|
||||
#powershell needs cmd.exe to preserve spaced args |
||||
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File" |
||||
win32.nextshelltype="powershell" |
||||
|
||||
win32.outputfile="runtime.cmd" |
||||
|
||||
Loading…
Reference in new issue