Browse Source

scriptapps update

master
Julian Noble 4 months ago
parent
commit
929782e083
  1. 798
      bin/getzig.cmd
  2. 0
      src/scriptapps/bin/getzig.bash
  3. 643
      src/scriptapps/bin/getzig.ps1
  4. 36
      src/scriptapps/bin/getzig_original.polyglot
  5. 42
      src/scriptapps/bin/getzig_wrap.toml
  6. 352
      src/scriptapps/getpunk.ps1
  7. 46
      src/scriptapps/getpunk_wrap.toml
  8. 832
      src/scriptapps/runtime.ps1
  9. 54
      src/scriptapps/runtime_wrap.toml

798
bin/getzig.cmd

@ -806,7 +806,13 @@ do if not defined param1 set %%~"param1=%2%%~"
rename set ""; rename S set; set k {-- "$@" "a}; if {[info exists ::env($k)]} {unset ::env($k)} ;# tidyup and restore rename set ""; rename S set; set k {-- "$@" "a}; if {[info exists ::env($k)]} {unset ::env($k)} ;# tidyup and restore
Hide :exit_multishell;Hide {<#};Hide '@ Hide :exit_multishell;Hide {<#};Hide '@
#--------------------------------------------------------------------- #---------------------------------------------------------------------
puts "info script : [info script]"
#puts "argcount : $::argc"
#puts "argvalues: $::argv"
#puts "argv0 : $::argv0"
# -- --- --- --- --- --- --- --- --- --- --- ---
#divert to configured nextshell #divert to configured nextshell
set script_as_called [info script]
package require platform package require platform
set plat_full [platform::generic] set plat_full [platform::generic]
set plat [lindex [split $plat_full -] 0] set plat [lindex [split $plat_full -] 0]
@ -819,6 +825,14 @@ set in_data 0
set nextshellpath "" set nextshellpath ""
set nextshelltype "" set nextshelltype ""
puts stderr "PLAT: $plat" puts stderr "PLAT: $plat"
switch -glob -- $plat {
"msys" - "mingw*" {
set os "win32"
}
default {
set os $plat
}
}
foreach ln [split $scriptdata \n] { foreach ln [split $scriptdata \n] {
if {[string trim $ln] eq ""} {continue} if {[string trim $ln] eq ""} {continue}
if {!$in_data} { if {!$in_data} {
@ -826,14 +840,14 @@ foreach ln [split $scriptdata \n] {
set in_data 1 set in_data 1
} }
} else { } else {
if {[string match "*@SET*nextshellpath?${plat}_*" $ln]} { if {[string match "*@SET*nextshellpath?${os}_*" $ln]} {
set lineparts [split $ln =] set lineparts [split $ln =]
set tail [lindex $lineparts 1] set tail [lindex $lineparts 1]
set nextshellpath [string trimright $tail {_"}] set nextshellpath [string trimright $tail {_"}]
if {$nextshellpath ne "" && $nextshelltype ne ""} { if {$nextshellpath ne "" && $nextshelltype ne ""} {
break break
} }
} elseif {[string match "*@SET*nextshelltype?${plat}_*" $ln]} { } elseif {[string match "*@SET*nextshelltype?${os}_*" $ln]} {
set lineparts [split $ln =] set lineparts [split $ln =]
set tail [lindex $lineparts 1] set tail [lindex $lineparts 1]
set nextshelltype [string trimright $tail {_"}] set nextshelltype [string trimright $tail {_"}]
@ -846,7 +860,6 @@ foreach ln [split $scriptdata \n] {
} }
} }
if {$nextshelltype ne "tcl" && $nextshelltype ne "none"} { if {$nextshelltype ne "tcl" && $nextshelltype ne "none"} {
set script_as_called [info script]
set script_rootname [file rootname $script_as_called] set script_rootname [file rootname $script_as_called]
if {$nextshelltype in "pwsh powershell"} { if {$nextshelltype in "pwsh powershell"} {
# experimental # experimental
@ -907,20 +920,52 @@ if {$nextshelltype ne "tcl" && $nextshelltype ne "none"} {
set scrname $script_as_called set scrname $script_as_called
set arglist $::argv set arglist $::argv
} }
puts stdout "tclsh launching subshell of type: $nextshelltype shellpath: $nextshellpath on script $scrname with args: $arglist"
#todo - handle /usr/bin/env #todo - handle /usr/bin/env
#todo - exitcode #todo - exitcode
if {[llength $nextshellpath] == 1 && [string index $nextshellpath 0] eq {"} && [string index $nextshellpath end] eq {"}} { #review - test spaced quoted words in nextshellpath?
set nextshell_words [list $nextshellpath] #
} else { #if {[llength $nextshellpath] == 1 && [string index $nextshellpath 0] eq {"} && [string index $nextshellpath end] eq {"}} {
set nextshell_words $nextshellpath # set nextshell_words [list $nextshellpath]
#} else {
# set nextshell_words $nextshellpath
#}
#perform any msys argument munging on a cmd/cmd.exe based nextshellpath before we convert the first word to an auto_exec path
switch -glob -- $plat {
"msys" - "mingw*" {
set cmdword [lindex $nextshellpath 0]
#we only act on cmd or cmd.exe - not a full path such as c:/WINDOWS/system32/cmd.exe
#the nextshellpath should generally be configured as cmd /c ... or cmd.exe ... but specifying it as a path could allow bypassing this un-munging.
#The un-munging only applies to msys/mingw, so such bypassing should be unnecessary - review
#maint: keep this munging in sync with zsh/bash and perl blocks which must also do msys mangling
if {[regexp {^cmd$|^cmd[.]exe$} $cmdword]} {
#need to deal with msys argument munging
puts stderr "cmd call via msys detected. performing translation of /c to //C"
#for now we only deal with /C or /c - todo - other cmd.exe flags?
#In this context we would usually only be using cmd.exe /c to launch older 'desktop' powershell to avoid spaced-argument problems - so we aren't expecting other flags
set new_nextshellpath [list $cmdword]
#for now - just do what zsh munging does - bash regex/string/array processing is tedious and footgunny for the unfamiliar (me),
#so determine the minimum viable case for code there, then port behaviour to perl/tcl msys munging sections.
foreach w [lrange $nextshellpath 1 end] {
if {[regexp {^/[Cc]$} $w]} {
lappend new_nextshellpath {//C}
} else {
lappend new_nextshellpath $w
}
}
set nextshellpath $new_nextshellpath
}
}
} }
set ns_firstword [lindex $nextshellpath 0] set ns_firstword [lindex $nextshellpath 0]
if {[string index $ns_firstword 0] eq {"} && [string index $ns_firstword end] eq {"}} { #review - is this test for extra layer of double quoting on first word really necessary?
set ns_firstword [string range $ns_firstword 1 end-1] #if we are treaing $nextshellpath as a tcl list - the first layer of double quotes will already have disappeared
} ##if {[string index $ns_firstword 0] eq {"} && [string index $ns_firstword end] eq {"}} {
## set ns_firstword [string range $ns_firstword 1 end-1]
##}
if {[string match {/*/env} $ns_firstword] && $::tcl_platform(platform) ne "windows"} { if {$::tcl_platform(platform) ne "windows" && [string match {/*/env} $ns_firstword]} {
set exec_part $nextshellpath set exec_part $nextshellpath
} else { } else {
set epath [auto_execok $ns_firstword] set epath [auto_execok $ns_firstword]
@ -930,6 +975,10 @@ if {$nextshelltype ne "tcl" && $nextshelltype ne "none"} {
set exec_part [list {*}$epath {*}[lrange $nextshellpath 1 end]] set exec_part [list {*}$epath {*}[lrange $nextshellpath 1 end]]
} }
} }
puts stdout "tclsh launching subshell of type: $nextshelltype shellpath: $nextshellpath on script $scrname with args: $arglist"
puts stdout "exec: $exec_part $scrname $arglist"
catch {exec {*}$exec_part $scrname {*}$arglist <@stdin >@stdout 2>@stderr} emsg eopts catch {exec {*}$exec_part $scrname {*}$arglist <@stdin >@stdout 2>@stderr} emsg eopts
if {[dict exists $eopts -errorcode]} { if {[dict exists $eopts -errorcode]} {
@ -973,11 +1022,6 @@ namespace eval ::punk::multishell {
} }
} }
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin Tcl Payload # -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin Tcl Payload
#puts "script : [info script]"
#puts "argcount : $::argc"
#puts "argvalues: $::argv"
#puts "argv0 : $::argv0"
# -- --- --- --- --- --- --- --- --- --- --- ---
#<tcl-payload> #<tcl-payload>
puts stderr "No tcl code for this script. Try another program such as zsh or bash or perl" puts stderr "No tcl code for this script. Try another program such as zsh or bash or perl"
@ -1006,7 +1050,7 @@ echo "var0: $0 @: $@"
# use oldschool backticks and sed (posix - lowest common denominator) \ # use oldschool backticks and sed (posix - lowest common denominator) \
# ps_shellname=`ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()' | sed -E 's/^.*\/|^-//'` \ # ps_shellname=`ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()' | sed -E 's/^.*\/|^-//'` \
# some ps impls will return arguments - so last field not always appropriate \ # some ps impls will return arguments - so last field not always appropriate \
# some ps impls don't have -o (e.g gnu cygwin) so ps_shellname may remain empty and emit an error \ # some ps impls don't have -o (e.g cygwin) so ps_shellname may remain empty and emit an error \
ps_shellname=`ps -o pid,comm -p $$ | awk '$1 != "PID" {print $2}'` ps_shellname=`ps -o pid,comm -p $$ | awk '$1 != "PID" {print $2}'`
# \ # \
echo "shell from ps: $ps_shellname" echo "shell from ps: $ps_shellname"
@ -1061,17 +1105,14 @@ if false==false # else {
then then
: # : #
# zsh/bash \ # zsh/bash \
shift && set -- "${@:1:$((${#@}-1))}" shift && set -- "${@:1:$((${#@}-1))}"
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### # ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- sh/bash script section # -- zsh/bash script section
# -- leave as is if all that is required is launching the Tcl payload"
# --
# -- Note that sh/bash script isn't called when running a .bat/.cmd from cmd.exe on windows by default
# -- adjust the %nextshell% value above
# -- if sh/bash scripting needs to run on windows too.
# -- # --
# -- review - for zsh do we want to use: setopt KSH_ARRAYS ?
# -- arrays in bash 0-based vs 1-based in zsh
# -- stick to the @:i:len syntax which is same for both
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### # ## ### ### ### ### ### ### ### ### ### ### ### ### ###
plat=$(uname -s) #platform/system plat=$(uname -s) #platform/system
@ -1094,7 +1135,6 @@ elif [[ "$plat" == "MINGW64"* ]]; then
elif [[ "$plat" == "CYGWIN_NT"* ]]; then elif [[ "$plat" == "CYGWIN_NT"* ]]; then
os="win32" os="win32"
elif [[ "$plat" == "MSYS_NT"* ]]; then elif [[ "$plat" == "MSYS_NT"* ]]; then
echo MSYS
#review.. #review..
#Need to consider the difference between when msys2 was launched (which strips some paths and sets up the environment) #Need to consider the difference between when msys2 was launched (which strips some paths and sets up the environment)
@ -1141,6 +1181,8 @@ elif [[ "$ps_shellname" == "zsh" ]]; then
else else
#fallback - doesn't seem to work in zsh - untested in early bash #fallback - doesn't seem to work in zsh - untested in early bash
IFS=$'\n' arr_oslines=($shellconfiglines) IFS=$'\n' arr_oslines=($shellconfiglines)
IFS=$' \t\n'
# review
fi fi
nextshellpath="" nextshellpath=""
nextshelltype="" nextshelltype=""
@ -1182,23 +1224,33 @@ if [[ "$nextshelltype" != "bash" && "$nextshelltype" != "none" ]]; then
fi fi
if [[ "$plat" == "MSYS_NT"* ]]; then if [[ "$plat" == "MSYS_NT"* ]]; then
#we need to deal with MSYS argument mangling #we need to deal with MSYS argument munging
cmdpattern="^cmd.exe |^cmd " cmdpattern="^cmd.exe |^cmd "
#do not double quote cmdpattern - or it will be treated as literal string #do not double quote cmdpattern - or it will be treated as literal string
if [[ "$nextshellpath" =~ $cmdpattern ]]; then if [[ "$nextshellpath" =~ $cmdpattern ]]; then
#for now - tell the user what's going on #for now - tell the user what's going on
echo "cmd call via msys detected. performing translation of /c to //c and escaping backslashes in script path" echo "cmd call via msys detected. performing translation of /c to //c and escaping backslashes in script path" >&2
#flags to cmd.exe such as /c are interpreted by msys as looking like a unix path #flags to cmd.exe such as /c are interpreted by msys as looking like a unix path
#review - for nextshellpath targets specified in the block for win32 - we don't expect unix paths (?) #review - for nextshellpath targets specified in the block for win32 - we don't expect unix paths (?)
#what about other flags? - can we just double up all forward slashes? #what about other flags? - can we just double up all forward slashes?
nextshellpath="${nextshellpath// \/c / \/\/c }" #maint: keep this munging in sync with the tcl block and perl block which must also do msys munging
echo "new nextshellpath: ${nextshellpath}" nextshellpath="${nextshellpath// \/[cC] / \/\/c }"
# echo "new nextshellpath: ${nextshellpath}"
#review -
#don't double quote this #don't double quote this
script=${script//\\/\\\\} script=${script//\\/\\\\}
fi fi
echo "calling ${nextshellpath} $script $@" echo "calling ${nextshellpath} $script $@"
# eval is required here - but why?
eval ${nextshellpath} "$script" "$@" #load into array
cmd_array=($nextshellpath)
cmd_array+=("$script") #add script, which may contain spaces as a single entry ?
cmd_array+=( "$@" ) #add each element of args to array as a separate entry (equiv ? "${arr[@]}")
# printf "%s\n" "${cmd_array[@]}"
"${cmd_array[@]}"
# this works to make nextshellpath run - but joins $@ members incorrectly
#eval ${nextshellpath} "$script" "$@"
else else
#e.g /usr/bin/env tclsh "$0" "$@" #e.g /usr/bin/env tclsh "$0" "$@"
${nextshellpath} "$script" "$@" ${nextshellpath} "$script" "$@"
@ -1308,8 +1360,33 @@ if 0 {
# -- unbalanced braces { } here *even in comments* will cause problems if there was no Tcl exit or return above # -- unbalanced braces { } here *even in comments* will cause problems if there was no Tcl exit or return above
# -- custom script should generally go below the begin_powershell_payload line # -- custom script should generally go below the begin_powershell_payload line
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### # ## ### ### ### ### ### ### ### ### ### ### ### ### ###
function GetScriptName { $myInvocation.ScriptName } #$MyInvocation.ScriptName should probably be considered deprecated
$scriptname = GetScriptName # https://stackoverflow.com/questions/78511229/how-can-i-choose-between-myinvocation-scriptname-and-myinvocation-pscommandpat
$runningscriptname = $PSCommandPath
if (-not $MyInvocation.PSCommandPath) {
$callingscriptname = ''
} else {
$callingscriptname = $MyInvocation.PSCommandPath
}
#The problem with psmodulepath
#https://github.com/PowerShell/PowerShell/issues/18108
# psmodulepath is shared by powershell and pwsh despite not all ps modules being compatible.
# It is futzed with by powershell/pwsh based on detecting the child process type.
# a psmodulepath that has been futzed with by pwsh will not work for a child powershell 5 process that isn't launched directly
#This is inherently unfriendly to situations where an intervening process may be something else such as cmd.exe,tcl,perl etc
# nevertheless, powershell/pwsh maintainers seem to have taken the MS-centric view of the world that such situations don't exist :/
#
#symptoms of these shenannigans not working include things like Get-FileHash failing in powershell desktop
#
#We don't know if the original console was pwsh/powershell or cmd.exe, and we need to potentially divert to powershell 5 (desktop)
#via tcl or perl etc - or cmd.exe
if ($PSVersionTable.PSVersion.Major -le 5) {
# For Windows PowerShell, we want to remove any PowerShell 7 paths from PSModulePath
#snipped from https://github.com/PowerShell/DSC/pull/777/commits/af9b99a4d38e0cf1e54c4bbd89cbb6a8a8598c4e
#Presumably users are supposed to know not to have custom paths for powershell desktop containing a 'powershell' subfolder??
$env:PSModulePath = ($env:PSModulePath -split ';' | Where-Object { $_ -notlike '*\powershell\*' }) -join ';'
}
function GetDynamicParamDictionary { function GetDynamicParamDictionary {
[CmdletBinding()] [CmdletBinding()]
param( param(
@ -1384,11 +1461,11 @@ function GetDynamicParamDictionary {
#} #}
#psmain @args #psmain @args
#"Timestamp : {0,10:yyyy-MM-dd HH:mm:ss}" -f $(Get-Date) | write-host #"Timestamp : {0,10:yyyy-MM-dd HH:mm:ss}" -f $(Get-Date) | write-host
"Script Name : {0}" -f $scriptname | write-host #"Running Script Name : {0}" -f $runningscriptname | write-host
"Powershell Version: {0}" -f $PSVersionTable.PSVersion.Major | write-host "Powershell Version: {0}" -f $PSVersionTable.PSVersion.Major | write-host
"powershell args : {0}" -f ($args -join ", ") | write-host #"powershell args : {0}" -f ($args -join ", ") | write-host
# -- --- --- --- # -- --- --- ---
$thisfileContent = Get-Content $scriptname -Raw $thisfileContent = Get-Content $runningscriptname -Raw
$startTag = ": <<asadmin_start>>" $startTag = ": <<asadmin_start>>"
$endTag = ": <<asadmin_end>>" $endTag = ": <<asadmin_end>>"
$pattern = "(?s)`n$startTag[^`n]*`n(.*?)`n$endTag" $pattern = "(?s)`n$startTag[^`n]*`n(.*?)`n$endTag"
@ -1487,7 +1564,7 @@ if ($match.Success) {
} }
if (-not (("pwsh", "powershell", "") -contains $nextshell_type)) { if (-not (("pwsh", "powershell", "") -contains $nextshell_type)) {
#nextshell diversion exists for this platform #nextshell diversion exists for this platform
write-host "os: $os pwsh/powershell launching subshell of type: $nextshell_type shellpath: $nextshell_path on script $scriptname" write-host "os: $os pwsh/powershell launching subshell of type: $nextshell_type shellpath: $nextshell_path on script $runningscriptname"
# $arguments = @($($MyInvocation.MyCommand.Path)) # $arguments = @($($MyInvocation.MyCommand.Path))
# $arguments += $args # $arguments += $args
@ -1495,7 +1572,7 @@ if ($match.Success) {
# $process = (Start-Process -FilePath $nextshell_path -ArgumentList $arguments -NoNewWindow -Wait) # $process = (Start-Process -FilePath $nextshell_path -ArgumentList $arguments -NoNewWindow -Wait)
# Exit $process.ExitCode # Exit $process.ExitCode
& $nextshell_path $scriptname $args & $nextshell_path $runningscriptname $args
exit $LASTEXITCODE exit $LASTEXITCODE
} }
} }
@ -1503,275 +1580,380 @@ if ($match.Success) {
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin powershell Payload # -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin powershell Payload
#<powershell-payload> #<powershell-payload>
#launch example #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 '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" #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? #Join-Path using verbose method to support powershell 5?
#$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.." #$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.."
$outbase = $PSScriptRoot $outbase = $PSScriptRoot
$outbase = Resolve-Path -Path $outbase $outbase = Resolve-Path -Path $outbase
Write-host "Base folder: $outbase" Write-host "Base folder: $outbase"
$toolsfolder = Join-Path -Path $outbase -ChildPath "tools" $toolsfolder = Join-Path -Path $outbase -ChildPath "tools"
if (-not(Test-Path -Path $toolsfolder -PathType Container)) { if (-not(Test-Path -Path $toolsfolder -PathType Container)) {
#create folder - (can include missing intermediaries) #create folder - (can include missing intermediaries)
New-Item -Path $toolsfolder -ItemType Directory New-Item -Path $toolsfolder -ItemType Directory
} }
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" $zigfolder = Join-Path $toolsfolder -ChildPath "zig"
$zigexe = Join-Path $zigfolder "zig.exe" $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.15.1.zip" ;#zip on windows, tarball on every other platform
Write-Output "powershell version: $($PSVersionTable.PSVersion)" $releasearchive = "zig-x86_64-windows-0.16.0-dev.254+6dd0270a1.zip"
Write-Output "powershell version: $($PSVersionTable.PSVersion)"
if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
Write-Host "zig.exe is installed in tools/zig" if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
$zigv = tools/zig/zig.exe version 2>&1 $relative_zigfolder = Resolve-Path -Path $zigfolder -RelativeBasePath $outbase -Relative
$stdout = $zigv | Where-Object {$_ -is [string]} Write-Host "zig.exe is installed in $relative_zigfolder"
$stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} $zigv = & $zigexe version 2>&1
if ($stderr) { $stdout = $zigv | Where-Object {$_ -is [string]}
Write-Host "Unexpected output from tools/zig/zig.exe: $stderr" $stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
Write-Host "Consider deleting tools/zig and re-downloading" if ($stderr) {
} else { Write-Host "Unexpected output from ${zigexe}: $stderr"
Write-Host "tools/zig/zig.exe version is: $stdout" Write-Host "Consider deleting $zigexe and re-downloading"
} } else {
exit Write-Host "$zigexe version is: $stdout"
} }
exit
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { }
Write-Host "minisign is available"
} else { if (Get-Command "minisign" -ErrorAction SilentlyContinue) {
Write-Host "minisign is missing. Will attempt to install using winget." Write-Host "minisign is available"
#Find-Module/Install-Module: older mechanism, available in powershell } else {
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? Write-Host "minisign is missing. Will attempt to install using winget."
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client #Find-Module/Install-Module: older mechanism, available in powershell
if (${wgclient}.Length -eq 0) { #Find-PSResource/Install-PSResource: only available in newer pwsh etc?
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." $wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
Install-PackageProvider -Name NuGet -Force if (${wgclient}.Length -eq 0) {
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy Write-Host "Microsoft.WinGet.Client module not installed.. will try to install."
if ($psgallery_existing_policy -eq "Untrusted") { Install-PackageProvider -Scope CurrentUser -Name NuGet -Force
#Applies to all versions of PowerShell for the user, and is persistent for current user. $psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted if ($psgallery_existing_policy -eq "Untrusted") {
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted #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
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Repair-WinGetPackageManager }
import-module -name Microsoft.Winget.client Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery
Repair-WinGetPackageManager
if ($psgallery_existing_policy -eq "Untrusted") { import-module -name Microsoft.Winget.client
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted
} if ($psgallery_existing_policy -eq "Untrusted") {
} else { Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted
Write-Host "Microsoft.WinGet.Client is available" }
} } else {
$wingetversion = (Find-WinGetPackage jedisct1.minisign).Version Write-Host "Microsoft.WinGet.Client is available"
if ($wingetversion) { }
Write-Host "Installing minisign version: ${wingetversion}" $wingetversion = (Find-WinGetPackage jedisct1.minisign).Version
Install-WinGetPackage -Id "jedisct1.minisign" if ($wingetversion) {
} else { Write-Host "Installing minisign version: ${wingetversion}"
Write-Host "Failed to find minisign using winget" Install-WinGetPackage -Id "jedisct1.minisign"
exit } else {
} Write-Host "Failed to find minisign using winget"
#refreshing the current session's path should make the new command available (required for powershell 5 at least) exit
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") }
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { #refreshing the current session's path should make the new command available (required for powershell 5 at least)
Write-Host "minisign is now available" $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
} else { if (Get-Command "minisign" -ErrorAction SilentlyContinue) {
Write-Host "minisign is still not available" Write-Host "minisign is now available"
#if we automatically relaunch - we could get stuck in a loop - ask user. } else {
$response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N" Write-Host "minisign is still not available"
#if ($PSVersionTable.PSEdition -eq "Desktop") { #if we automatically relaunch - we could get stuck in a loop - ask user.
#powershell.exe $response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N"
#} else { #if ($PSVersionTable.PSEdition -eq "Desktop") {
#pwsh.exe #powershell.exe
#} #} else {
if ($response -ieq "y") { #pwsh.exe
Start-Process 'getzig.cmd' -NoNewWindow -Wait #}
} if ($response -ieq "y") {
exit 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) #extract_zip to be called only after sig verified
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 function extractZip {
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") [CmdletBinding()]
$mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n" param(
#$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry [Parameter(Mandatory=$true, Position = 0)][string] $releasearchive,
$mirror_array += "https://ziglang.org" #main site [Parameter(Mandatory=$true, Position = 1)] [string] $toolsfolder
)
$dict_mirrors = [ordered]@{} Add-Type -Assembly "System.IO.Compression.Filesystem"
$host_list = @() #same ordering as dict_mirrors $outfile = Join-Path $toolsfolder -ChildPath $releasearchive
foreach ($mirror in $mirror_array) {
$uri = New-Object System.Uri($mirror) $zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive)
$hostname = $uri.Host if (-not ($zip_rootname.Contains("zig"))) {
$dict_mirrors[$hostname] = @{} write-host "sanity check on zip_rootname '$zip_rootname' failed - aborting"
$dict_mirrors[$hostname]["uri"] = $mirror exit 1
$dict_mirrors[$hostname]["latency"] = 888888 ;#default }
$host_list += $hostname $zip_extraction_folder = Join-Path -Path $toolsfolder -ChildPath $zip_rootname
#write-host "Host name: $hostname" if (Test-Path -Path $zip_extraction_folder -PathType Container) {
} write-host "Existing folder found at $zip_extraction_folder - removing folder prior to extraction"
#write-host "dict: $($dict_mirrors | out-String)" Remove-Item -Path $zip_extraction_folder -Recurse -Force -ErrorAction SilentlyContinue
write-host "host_list: $host_list" }
$automation_name = "punkshell+julian@precisium.com.au_target_by_latency" #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)
#test-netconnection progressbar seems not-so-well-behaved (prog bar lingers) Write-Host " - archive extracted."
#test-netconnection a function not cmdlet? Seems to need setting at global level if (-not (Test-Path -Path $zip_extraction_folder -PathType Container)) {
$OriginalProgressPreference = $Global:ProgressPreference write-host "Failed to verify extraction as folder at $zip_extraction_folder"
$Global:ProgressPreference = 'SilentlyContinue' exit 1
#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 $zigfolder = Join-Path $toolsfolder -ChildPath "zig"
if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) { $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$host_list += $ihost
$dict_mirrors[$ihost] = @{} $retries = 10
$dict_mirrors[$ihost]["latency"] = 1 $exe_missing = $true #missing until tested as a found leaf
$dict_mirrors[$ihost]["uri"] = $imirror $sleep_time = 2
} while (($retries -gt 0) -and $exe_missing) {
$trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore $retries -= 1
$Global:ProgressPreference = $OriginalProgressPreference #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)
if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) { #https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory
$dict_mirrors["gitea1.intx.com.au"]["latency"] = 2
#short-circuit for hosts very near gitea1.intx.com.au #In some cases just the GC was enough.. but in other cases even sleep 3 seconds + GC didn't work
#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. #sleep of 5 seems more reliable - but the size of the required delay may depend on what is running on the system,
} else { # and the size of the extracted folder etc.
if ($PSVersionTable.PSEdition -eq "Desktop") { #Rather than use a large sleep to cover all cases - we use a limited retry loop with a somewhat shorter sleep e.g 2
#powershell.exe Write-Host "waiting $sleep_time seconds and also running GC to allow locks to clear. Max remaining retries: $retries"
#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 start-sleep -Seconds $sleep_time
$test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore
for ($i = 0; $i -lt $test_results.Count; $i++) { [GC]::Collect()
$result = $test_results[$i] [GC]::WaitForPendingFinalizers()
if ($result) { # -------------------------------------
$targethost = $result.Address #Remove-Item -Path "$outfile"
if ($result.StatusCode -eq 0) { #write-host "zip_rootname: $zip_rootname"
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime write-host "Attempting to move $zip_extraction_folder to ${zigfolder}"
} else { Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder -ErrorAction SilentlyContinue
$dict_mirrors[$targethost]["latency"] = 999999 if (-not $?) {
} write-host "Renaming extracted folder into place at $zigfolder failed"
} else { write-host " - error message: $($error[0].Exception.Message)"
$targethost = $host_list[$i] }
$dict_mirrors[$targethost]["latency"] = 999999 if (Test-Path -Path $zigexe -PathType leaf) {
} $exe_missing = $false
} }
} else { }
#pwsh.exe
$test_results = Test-Connection -TargetName $host_list -Count 1 -Ipv4 -Detailed -TcpPort 443 -Quiet if (Test-Path -Path $zigexe -PathType leaf) {
for ($i = 0; $i -lt $test_results.Count; $i++) { Write-Host "Zig installed in ${zigfolder}"
$result = $test_results[$i] return $true
if ($result) { } else {
$targethost = $result.Target Write-Host "Failed to install as $zigexe"
if ($result.Status -eq "Success") { return $false
$dict_mirrors[$targethost]["latency"] = $result.Latency }
} else { }
$dict_mirrors[$targethost]["latency"] = 999999
}
} else { $zigpubkey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"
$targethost = $host_list[$i]
$dict_mirrors[$targethost]["latency"] = 999999 $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
$list_mirror_dicts = @() $stdout = $sigresult | Where-Object {$_ -is [string]}
#write-host "dict tested: $($dict_mirrors | Out-String)" $stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
foreach ($key in $dict_mirrors.Keys) { $is_valid = $false
$list_mirror_dicts += $($dict_mirrors[$key]) if ($stderr) {
} write-host "Signature validation failed with message: $stderr"
#need to ensure latency cast to integer (on powershell 5 at least) } else {
$sorted_mirror_dicts = $list_mirror_dicts | Sort-Object -Property { [int]$_.latency } if (($stdout | Out-String).Contains("signature verified")) {
#Write-Host "Sorted by latency: $($sorted_mirror_dicts | Format-Table -AutoSize | Out-String)" write-host $stdout
Write-Host "Sorted by latency: $($sorted_mirror_dicts | Out-String)" $is_valid = $true
} else {
foreach ($hostinfo in $sorted_mirror_dicts) { write-host "Unexpected output from minisign: $stdout"
$uristring = $hostinfo.uri write-host "Did not contain 'signature verified'"
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}" if (-not($is_valid)) {
} else { write-Host "Couldn't verify signature of existing $outfile with $outfile.minisig"
$full_uristring = "${uristring}/${releasearchive}?source=${automation_name}" Remove-Item -Path $outfile -ErrorAction SilentlyContinue
$sig_uristring = "${uristring}/${releasearchive}.minisig?source=${automation_name}" Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue
} } else {
Write-Host "Downloading zig from $full_uristring" $download_required = $false
#$uriobj = [uri]$full_uristring }
#$lastSegment = $uriobj.Segments[-1] }
#$outfile = Join-Path $toolsfolder -ChildPath $lastSegment }
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive if (-not $download_required) {
Write-Host "Download to: $outfile" write-host "Existing zip and zip.minisig ok - download not required"
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile Write-Host "Signature OK - extracting existing archive ..."
$null = extractZip $releasearchive $toolsfolder
if (-not(Test-Path -Path $outfile -PathType Leaf)) {
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
continue $v = Invoke-Expression "$zigexe version"
} Write-Host "ZIG VERSION: ${v}"
Write-Host "Downloading minisig signature from $sig_uristring" exit 0
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" $mirrors_url = "https://ziglang.org/download/community-mirrors.txt"
continue $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
write-host "downloaded $outfile and ${outfile}.minisig - validating signature..." $mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools")
#validate releasearchive (tarball/zip) $mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n"
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 #$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry
$stdout = $sigresult | Where-Object {$_ -is [string]} $mirror_array += "https://ziglang.org" #main site
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
$is_valid = $false $dict_mirrors = [ordered]@{}
if ($stderr) { $host_list = @() #same ordering as dict_mirrors
write-host "Signature validation failed with message: $stderr" foreach ($mirror in $mirror_array) {
} else { $uri = New-Object System.Uri($mirror)
if (($stdout | Out-String).Contains("signature verified")) { $hostname = $uri.Host
write-host $stdout $dict_mirrors[$hostname] = @{}
$is_valid = $true $dict_mirrors[$hostname]["uri"] = $mirror
} else { $dict_mirrors[$hostname]["latency"] = 888888 ;#default
write-host "Unexpected output from minisign: $stdout" $host_list += $hostname
write-host "Did not contain 'signature verified'" #write-host "Host name: $hostname"
} }
} #write-host "dict: $($dict_mirrors | out-String)"
if (-not($is_valid)) { write-host "host_list: $host_list"
write-Host "Couldn't verify signature from download site $uristring" $automation_name = "punkshell+julian@precisium.com.au_target_by_latency"
Remove-Item -Path $outfile -ErrorAction SilentlyContinue
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue
continue #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
Write-Host "Signature OK - extracting archive ..." $Global:ProgressPreference = '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. #temporary dev download source
# ------------------------------------- $ihost = "10.30.30.107"
Add-Type -Assembly "System.IO.Compression.Filesystem" $imirror = "http://10.30.30.107/jn/punkbin/raw/branch/master/win32-x86_64/tools"
[System.IO.Compression.Zipfile]::ExtractToDirectory($outfile, $toolsfolder) $itrace = test-netconnection $ihost -Hops 6 -TraceRoute -ErrorAction Ignore
Write-Host " - archive extracted." if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) {
#We *intermittently* get permission errors when trying to rename the resulting folder (possibly also if we try to delete the zip file immediately) $host_list += $ihost
#There seems to be some sort of lock held after ExtractToDirectory (possibly AV related) $dict_mirrors[$ihost] = @{}
#https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory $dict_mirrors[$ihost]["latency"] = 1
[GC]::Collect() $dict_mirrors[$ihost]["uri"] = $imirror
[GC]::WaitForPendingFinalizers() }
# ------------------------------------- $trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore
$Global:ProgressPreference = $OriginalProgressPreference
#Remove-Item -Path "$outfile"
$zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive) if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) {
#Rename-Item -Path $dict_mirrors["gitea1.intx.com.au"]["latency"] = 2
#write-host "zip_rootname: $zip_rootname" #short-circuit for hosts very near gitea1.intx.com.au
write-host "moving $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) to ${zigfolder}" #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.
Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder } else {
Write-Host "Zig installed in ${zigfolder}" if ($PSVersionTable.PSEdition -eq "Desktop") {
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" #powershell.exe
$v = Invoke-Expression "$zigexe version" #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
Write-Host "ZIG VERSION: ${v}" $test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore
$test_ok = 1 ;#todo for ($i = 0; $i -lt $test_results.Count; $i++) {
if ($test_ok) { $result = $test_results[$i]
break if ($result) {
} $targethost = $result.Address
} if ($result.StatusCode -eq 0) {
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime
} else { } else {
Write-Host "Unable to retrieve list of zig community mirrors from $mirrors_url" $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"
}
#</powershell-payload> #</powershell-payload>

0
src/scriptapps/getzig.bash → src/scriptapps/bin/getzig.bash

643
src/scriptapps/getzig.ps1 → src/scriptapps/bin/getzig.ps1

@ -1,269 +1,374 @@
#launch example #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 '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" #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? #Join-Path using verbose method to support powershell 5?
#$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.." #$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.."
$outbase = $PSScriptRoot $outbase = $PSScriptRoot
$outbase = Resolve-Path -Path $outbase $outbase = Resolve-Path -Path $outbase
Write-host "Base folder: $outbase" Write-host "Base folder: $outbase"
$toolsfolder = Join-Path -Path $outbase -ChildPath "tools" $toolsfolder = Join-Path -Path $outbase -ChildPath "tools"
if (-not(Test-Path -Path $toolsfolder -PathType Container)) { if (-not(Test-Path -Path $toolsfolder -PathType Container)) {
#create folder - (can include missing intermediaries) #create folder - (can include missing intermediaries)
New-Item -Path $toolsfolder -ItemType Directory New-Item -Path $toolsfolder -ItemType Directory
} }
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" $zigfolder = Join-Path $toolsfolder -ChildPath "zig"
$zigexe = Join-Path $zigfolder "zig.exe" $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.15.1.zip" ;#zip on windows, tarball on every other platform
Write-Output "powershell version: $($PSVersionTable.PSVersion)" $releasearchive = "zig-x86_64-windows-0.16.0-dev.254+6dd0270a1.zip"
Write-Output "powershell version: $($PSVersionTable.PSVersion)"
if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
Write-Host "zig.exe is installed in tools/zig" if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
$zigv = tools/zig/zig.exe version 2>&1 $relative_zigfolder = Resolve-Path -Path $zigfolder -RelativeBasePath $outbase -Relative
$stdout = $zigv | Where-Object {$_ -is [string]} Write-Host "zig.exe is installed in $relative_zigfolder"
$stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} $zigv = & $zigexe version 2>&1
if ($stderr) { $stdout = $zigv | Where-Object {$_ -is [string]}
Write-Host "Unexpected output from tools/zig/zig.exe: $stderr" $stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
Write-Host "Consider deleting tools/zig and re-downloading" if ($stderr) {
} else { Write-Host "Unexpected output from ${zigexe}: $stderr"
Write-Host "tools/zig/zig.exe version is: $stdout" Write-Host "Consider deleting $zigexe and re-downloading"
} } else {
exit Write-Host "$zigexe version is: $stdout"
} }
exit
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { }
Write-Host "minisign is available"
} else { if (Get-Command "minisign" -ErrorAction SilentlyContinue) {
Write-Host "minisign is missing. Will attempt to install using winget." Write-Host "minisign is available"
#Find-Module/Install-Module: older mechanism, available in powershell } else {
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? Write-Host "minisign is missing. Will attempt to install using winget."
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client #Find-Module/Install-Module: older mechanism, available in powershell
if (${wgclient}.Length -eq 0) { #Find-PSResource/Install-PSResource: only available in newer pwsh etc?
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." $wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
Install-PackageProvider -Name NuGet -Force if (${wgclient}.Length -eq 0) {
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy Write-Host "Microsoft.WinGet.Client module not installed.. will try to install."
if ($psgallery_existing_policy -eq "Untrusted") { Install-PackageProvider -Scope CurrentUser -Name NuGet -Force
#Applies to all versions of PowerShell for the user, and is persistent for current user. $psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted if ($psgallery_existing_policy -eq "Untrusted") {
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted #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
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Repair-WinGetPackageManager }
import-module -name Microsoft.Winget.client Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery
Repair-WinGetPackageManager
if ($psgallery_existing_policy -eq "Untrusted") { import-module -name Microsoft.Winget.client
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted
} if ($psgallery_existing_policy -eq "Untrusted") {
} else { Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted
Write-Host "Microsoft.WinGet.Client is available" }
} } else {
$wingetversion = (Find-WinGetPackage jedisct1.minisign).Version Write-Host "Microsoft.WinGet.Client is available"
if ($wingetversion) { }
Write-Host "Installing minisign version: ${wingetversion}" $wingetversion = (Find-WinGetPackage jedisct1.minisign).Version
Install-WinGetPackage -Id "jedisct1.minisign" if ($wingetversion) {
} else { Write-Host "Installing minisign version: ${wingetversion}"
Write-Host "Failed to find minisign using winget" Install-WinGetPackage -Id "jedisct1.minisign"
exit } else {
} Write-Host "Failed to find minisign using winget"
#refreshing the current session's path should make the new command available (required for powershell 5 at least) exit
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") }
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { #refreshing the current session's path should make the new command available (required for powershell 5 at least)
Write-Host "minisign is now available" $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
} else { if (Get-Command "minisign" -ErrorAction SilentlyContinue) {
Write-Host "minisign is still not available" Write-Host "minisign is now available"
#if we automatically relaunch - we could get stuck in a loop - ask user. } else {
$response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N" Write-Host "minisign is still not available"
#if ($PSVersionTable.PSEdition -eq "Desktop") { #if we automatically relaunch - we could get stuck in a loop - ask user.
#powershell.exe $response = read-host -Prompt "Relaunching process may make minizip available. Relaunch? Y|N"
#} else { #if ($PSVersionTable.PSEdition -eq "Desktop") {
#pwsh.exe #powershell.exe
#} #} else {
if ($response -ieq "y") { #pwsh.exe
Start-Process 'getzig.cmd' -NoNewWindow -Wait #}
} if ($response -ieq "y") {
exit 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) #extract_zip to be called only after sig verified
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 function extractZip {
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") [CmdletBinding()]
$mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n" param(
#$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry [Parameter(Mandatory=$true, Position = 0)][string] $releasearchive,
$mirror_array += "https://ziglang.org" #main site [Parameter(Mandatory=$true, Position = 1)] [string] $toolsfolder
)
$dict_mirrors = [ordered]@{} Add-Type -Assembly "System.IO.Compression.Filesystem"
$host_list = @() #same ordering as dict_mirrors $outfile = Join-Path $toolsfolder -ChildPath $releasearchive
foreach ($mirror in $mirror_array) {
$uri = New-Object System.Uri($mirror) $zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive)
$hostname = $uri.Host if (-not ($zip_rootname.Contains("zig"))) {
$dict_mirrors[$hostname] = @{} write-host "sanity check on zip_rootname '$zip_rootname' failed - aborting"
$dict_mirrors[$hostname]["uri"] = $mirror exit 1
$dict_mirrors[$hostname]["latency"] = 888888 ;#default }
$host_list += $hostname $zip_extraction_folder = Join-Path -Path $toolsfolder -ChildPath $zip_rootname
#write-host "Host name: $hostname" if (Test-Path -Path $zip_extraction_folder -PathType Container) {
} write-host "Existing folder found at $zip_extraction_folder - removing folder prior to extraction"
#write-host "dict: $($dict_mirrors | out-String)" Remove-Item -Path $zip_extraction_folder -Recurse -Force -ErrorAction SilentlyContinue
write-host "host_list: $host_list" }
$automation_name = "punkshell+julian@precisium.com.au_target_by_latency" #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)
#test-netconnection progressbar seems not-so-well-behaved (prog bar lingers) Write-Host " - archive extracted."
#test-netconnection a function not cmdlet? Seems to need setting at global level if (-not (Test-Path -Path $zip_extraction_folder -PathType Container)) {
$OriginalProgressPreference = $Global:ProgressPreference write-host "Failed to verify extraction as folder at $zip_extraction_folder"
$Global:ProgressPreference = 'SilentlyContinue' exit 1
#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 $zigfolder = Join-Path $toolsfolder -ChildPath "zig"
if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) { $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$host_list += $ihost
$dict_mirrors[$ihost] = @{} $retries = 10
$dict_mirrors[$ihost]["latency"] = 1 $exe_missing = $true #missing until tested as a found leaf
$dict_mirrors[$ihost]["uri"] = $imirror $sleep_time = 2
} while (($retries -gt 0) -and $exe_missing) {
$trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore $retries -= 1
$Global:ProgressPreference = $OriginalProgressPreference #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)
if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) { #https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory
$dict_mirrors["gitea1.intx.com.au"]["latency"] = 2
#short-circuit for hosts very near gitea1.intx.com.au #In some cases just the GC was enough.. but in other cases even sleep 3 seconds + GC didn't work
#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. #sleep of 5 seems more reliable - but the size of the required delay may depend on what is running on the system,
} else { # and the size of the extracted folder etc.
if ($PSVersionTable.PSEdition -eq "Desktop") { #Rather than use a large sleep to cover all cases - we use a limited retry loop with a somewhat shorter sleep e.g 2
#powershell.exe Write-Host "waiting $sleep_time seconds and also running GC to allow locks to clear. Max remaining retries: $retries"
#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 start-sleep -Seconds $sleep_time
$test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore
for ($i = 0; $i -lt $test_results.Count; $i++) { [GC]::Collect()
$result = $test_results[$i] [GC]::WaitForPendingFinalizers()
if ($result) { # -------------------------------------
$targethost = $result.Address #Remove-Item -Path "$outfile"
if ($result.StatusCode -eq 0) { #write-host "zip_rootname: $zip_rootname"
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime write-host "Attempting to move $zip_extraction_folder to ${zigfolder}"
} else { Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder -ErrorAction SilentlyContinue
$dict_mirrors[$targethost]["latency"] = 999999 if (-not $?) {
} write-host "Renaming extracted folder into place at $zigfolder failed"
} else { write-host " - error message: $($error[0].Exception.Message)"
$targethost = $host_list[$i] }
$dict_mirrors[$targethost]["latency"] = 999999 if (Test-Path -Path $zigexe -PathType leaf) {
} $exe_missing = $false
} }
} else { }
#pwsh.exe
$test_results = Test-Connection -TargetName $host_list -Count 1 -Ipv4 -Detailed -TcpPort 443 -Quiet if (Test-Path -Path $zigexe -PathType leaf) {
for ($i = 0; $i -lt $test_results.Count; $i++) { Write-Host "Zig installed in ${zigfolder}"
$result = $test_results[$i] return $true
if ($result) { } else {
$targethost = $result.Target Write-Host "Failed to install as $zigexe"
if ($result.Status -eq "Success") { return $false
$dict_mirrors[$targethost]["latency"] = $result.Latency }
} else { }
$dict_mirrors[$targethost]["latency"] = 999999
}
} else { $zigpubkey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"
$targethost = $host_list[$i]
$dict_mirrors[$targethost]["latency"] = 999999 $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
$list_mirror_dicts = @() $stdout = $sigresult | Where-Object {$_ -is [string]}
#write-host "dict tested: $($dict_mirrors | Out-String)" $stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
foreach ($key in $dict_mirrors.Keys) { $is_valid = $false
$list_mirror_dicts += $($dict_mirrors[$key]) if ($stderr) {
} write-host "Signature validation failed with message: $stderr"
#need to ensure latency cast to integer (on powershell 5 at least) } else {
$sorted_mirror_dicts = $list_mirror_dicts | Sort-Object -Property { [int]$_.latency } if (($stdout | Out-String).Contains("signature verified")) {
#Write-Host "Sorted by latency: $($sorted_mirror_dicts | Format-Table -AutoSize | Out-String)" write-host $stdout
Write-Host "Sorted by latency: $($sorted_mirror_dicts | Out-String)" $is_valid = $true
} else {
foreach ($hostinfo in $sorted_mirror_dicts) { write-host "Unexpected output from minisign: $stdout"
$uristring = $hostinfo.uri write-host "Did not contain 'signature verified'"
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}" if (-not($is_valid)) {
} else { write-Host "Couldn't verify signature of existing $outfile with $outfile.minisig"
$full_uristring = "${uristring}/${releasearchive}?source=${automation_name}" Remove-Item -Path $outfile -ErrorAction SilentlyContinue
$sig_uristring = "${uristring}/${releasearchive}.minisig?source=${automation_name}" Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue
} } else {
Write-Host "Downloading zig from $full_uristring" $download_required = $false
#$uriobj = [uri]$full_uristring }
#$lastSegment = $uriobj.Segments[-1] }
#$outfile = Join-Path $toolsfolder -ChildPath $lastSegment }
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive if (-not $download_required) {
Write-Host "Download to: $outfile" write-host "Existing zip and zip.minisig ok - download not required"
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile Write-Host "Signature OK - extracting existing archive ..."
$null = extractZip $releasearchive $toolsfolder
if (-not(Test-Path -Path $outfile -PathType Leaf)) {
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
continue $v = Invoke-Expression "$zigexe version"
} Write-Host "ZIG VERSION: ${v}"
Write-Host "Downloading minisig signature from $sig_uristring" exit 0
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" $mirrors_url = "https://ziglang.org/download/community-mirrors.txt"
continue $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
write-host "downloaded $outfile and ${outfile}.minisig - validating signature..." $mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools")
#validate releasearchive (tarball/zip) $mirror_array += $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n"
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 #$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry
$stdout = $sigresult | Where-Object {$_ -is [string]} $mirror_array += "https://ziglang.org" #main site
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]}
$is_valid = $false $dict_mirrors = [ordered]@{}
if ($stderr) { $host_list = @() #same ordering as dict_mirrors
write-host "Signature validation failed with message: $stderr" foreach ($mirror in $mirror_array) {
} else { $uri = New-Object System.Uri($mirror)
if (($stdout | Out-String).Contains("signature verified")) { $hostname = $uri.Host
write-host $stdout $dict_mirrors[$hostname] = @{}
$is_valid = $true $dict_mirrors[$hostname]["uri"] = $mirror
} else { $dict_mirrors[$hostname]["latency"] = 888888 ;#default
write-host "Unexpected output from minisign: $stdout" $host_list += $hostname
write-host "Did not contain 'signature verified'" #write-host "Host name: $hostname"
} }
} #write-host "dict: $($dict_mirrors | out-String)"
if (-not($is_valid)) { write-host "host_list: $host_list"
write-Host "Couldn't verify signature from download site $uristring" $automation_name = "punkshell+julian@precisium.com.au_target_by_latency"
Remove-Item -Path $outfile -ErrorAction SilentlyContinue
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue
continue #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
Write-Host "Signature OK - extracting archive ..." $Global:ProgressPreference = '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. #temporary dev download source
# ------------------------------------- $ihost = "10.30.30.107"
Add-Type -Assembly "System.IO.Compression.Filesystem" $imirror = "http://10.30.30.107/jn/punkbin/raw/branch/master/win32-x86_64/tools"
[System.IO.Compression.Zipfile]::ExtractToDirectory($outfile, $toolsfolder) $itrace = test-netconnection $ihost -Hops 6 -TraceRoute -ErrorAction Ignore
Write-Host " - archive extracted." if ((${itrace}.PingSucceeded) -and (${itrace}.TraceRoute.Count -lt 5)) {
#We *intermittently* get permission errors when trying to rename the resulting folder (possibly also if we try to delete the zip file immediately) $host_list += $ihost
#There seems to be some sort of lock held after ExtractToDirectory (possibly AV related) $dict_mirrors[$ihost] = @{}
#https://stackoverflow.com/questions/74582293/file-lock-issues-on-zip-file-after-io-compression-zipfileextracttodirectory $dict_mirrors[$ihost]["latency"] = 1
[GC]::Collect() $dict_mirrors[$ihost]["uri"] = $imirror
[GC]::WaitForPendingFinalizers() }
# ------------------------------------- $trace = test-netconnection gitea1.intx.com.au -Hops 6 -TraceRoute -ErrorAction Ignore
$Global:ProgressPreference = $OriginalProgressPreference
#Remove-Item -Path "$outfile"
$zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive) if ((${trace}.PingSucceeded) -and (${trace}.TraceRoute.Count -lt 5)) {
#Rename-Item -Path $dict_mirrors["gitea1.intx.com.au"]["latency"] = 2
#write-host "zip_rootname: $zip_rootname" #short-circuit for hosts very near gitea1.intx.com.au
write-host "moving $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) to ${zigfolder}" #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.
Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder } else {
Write-Host "Zig installed in ${zigfolder}" if ($PSVersionTable.PSEdition -eq "Desktop") {
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" #powershell.exe
$v = Invoke-Expression "$zigexe version" #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
Write-Host "ZIG VERSION: ${v}" $test_results = Test-Connection $host_list -Count 1 -ErrorAction Ignore
$test_ok = 1 ;#todo for ($i = 0; $i -lt $test_results.Count; $i++) {
if ($test_ok) { $result = $test_results[$i]
break if ($result) {
} $targethost = $result.Address
} if ($result.StatusCode -eq 0) {
$dict_mirrors[$targethost]["latency"] = $result.ResponseTime
} else { } else {
Write-Host "Unable to retrieve list of zig community mirrors from $mirrors_url" $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"
}

36
src/scriptapps/getzig_original.polyglot → src/scriptapps/bin/getzig_original.polyglot

@ -1,18 +1,18 @@
#!/bin/sh #!/bin/sh
echo `# <#` echo `# <#`
mkdir -p ./zig 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 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 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 rm ./zig/zig-linux-x86_64-0.10.1.tar.xz
echo "Zig installed." echo "Zig installed."
./zig/zig version ./zig/zig version
exit exit
#> > $null #> > $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" 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 Expand-Archive -Path ".\zig-windows-x86_64-0.10.1.zip" -DestinationPath ".\" -Force
Remove-Item -Path " .\zig-windows-x86_64-0.10.1.zip" Remove-Item -Path " .\zig-windows-x86_64-0.10.1.zip"
Rename-Item -Path ".\zig-windows-x86_64-0.10.1" -NewName ".\zig" Rename-Item -Path ".\zig-windows-x86_64-0.10.1" -NewName ".\zig"
Write-Host "Zig installed." Write-Host "Zig installed."
./zig/zig.exe version ./zig/zig.exe version

42
src/scriptapps/getzig_wrap.toml → src/scriptapps/bin/getzig_wrap.toml

@ -1,21 +1,21 @@
[application] [application]
template="punk.multishell.cmd" template="punk.multishell.cmd"
as_admin=false as_admin=false
scripts=[ scripts=[
"getzig.ps1", "getzig.ps1",
"getzig.bash" "getzig.bash"
] ]
default_outputfile="getzig.cmd" default_outputfile="getzig.cmd"
default_nextshellpath="/usr/bin/env bash" default_nextshellpath="/usr/bin/env bash"
default_nextshelltype="bash" default_nextshelltype="bash"
#valid nextshelltype entries are: tcl perl pwsh powershell bash. #valid nextshelltype entries are: tcl perl pwsh powershell bash.
#nextshellpath entries must be 64 characters or less. #nextshellpath entries must be 64 characters or less.
win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c" win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c"
win32.nextshelltype="pwsh" win32.nextshelltype="pwsh"
win32.outputfile="getzig.cmd" win32.outputfile="getzig.cmd"

352
src/scriptapps/getpunk.ps1

@ -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" #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 #todo - support either fossil or git
#check if git available #check if git available
#if not, check/install winget, winget git #if not, check/install winget, winget git
$git_upstream = "https://gitea1.intx.com.au/jn/punkshell.git" $git_upstream = "https://gitea1.intx.com.au/jn/punkshell.git"
$launchdir = Get-Location #store original CWD $launchdir = Get-Location #store original CWD
$scriptfolder = Resolve-Path (Split-Path -Path $PSCommandPath -Parent) $scriptfolder = Resolve-Path (Split-Path -Path $PSCommandPath -Parent)
$punkfolder = "" $punkfolder = ""
$scriptroot = "$([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath))" $scriptroot = "$([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath))"
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) { if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) {
Write-Host "The git command doesn't seem to be available. Will attempt to install using winget." 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-Module/Install-Module: older mechanism, available in powershell
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? #Find-PSResource/Install-PSResource: only available in newer pwsh etc?
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client $wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client
if (${wgclient}.Length -eq 0) { if (${wgclient}.Length -eq 0) {
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." Write-Host "Microsoft.WinGet.Client module not installed.. will try to install."
Install-PackageProvider -Name NuGet -Force Install-PackageProvider -Name NuGet -Force
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy $psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy
if ($psgallery_existing_policy -eq "Untrusted") { if ($psgallery_existing_policy -eq "Untrusted") {
#Applies to all versions of PowerShell for the user, and is persistent for current user. #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 #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 Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
} }
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery
Repair-WinGetPackageManager Repair-WinGetPackageManager
import-module -name Microsoft.Winget.client import-module -name Microsoft.Winget.client
if ($psgallery_existing_policy -eq "Untrusted") { if ($psgallery_existing_policy -eq "Untrusted") {
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted
} }
} else { } else {
Write-Host "Microsoft.WinGet.Client is available" Write-Host "Microsoft.WinGet.Client is available"
} }
$gitversion = (Find-WinGetPackage Git.Git).Version $gitversion = (Find-WinGetPackage Git.Git).Version
if ($gitversion) { if ($gitversion) {
Write-Host "Installing git version: ${gitversion}" Write-Host "Installing git version: ${gitversion}"
Install-WinGetPackage -Id "Git.Git" Install-WinGetPackage -Id "Git.Git"
} else { } else {
Write-Host "Failed to find git using winget" Write-Host "Failed to find git using winget"
exit exit
} }
#refreshing the current session's path should make the new command available (required for powershell 5 at least) #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") $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
if (Get-Command "git" -ErrorAction SilentlyContinue) { if (Get-Command "git" -ErrorAction SilentlyContinue) {
Write-Host "git is now available" Write-Host "git is now available"
} else { } else {
Write-Host "git is still not available" Write-Host "git is still not available"
Write-HOst "Please install Git or relaunch your terminal and check it is available on the path." Write-HOst "Please install Git or relaunch your terminal and check it is available on the path."
exit exit
} }
} }
if (($launchdir.Path) -ne ($scriptfolder.Path)) { 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." 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: " $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") { if ($answer -match "y") {
$punkfolder = $launchdir $punkfolder = $launchdir
} elseif ($answer -match "n") { } elseif ($answer -match "n") {
$punkfolder = $scriptfolder $punkfolder = $scriptfolder
} else { } else {
exit 1 exit 1
} }
} else { } else {
$punkfolder = $scriptfolder $punkfolder = $scriptfolder
} }
$punkfoldercontents = Get-ChildItem -Path $punkfolder -Force #include possibly hidden items such as .git folder $punkfoldercontents = Get-ChildItem -Path $punkfolder -Force #include possibly hidden items such as .git folder
$contentcount = ( $punkfoldercontents | Measure-Object).Count $contentcount = ( $punkfoldercontents | Measure-Object).Count
$effectively_empty = 0 $effectively_empty = 0
if ($contentcount -eq 0) { if ($contentcount -eq 0) {
$effectively_empty = 1 $effectively_empty = 1
} elseif ($punkfolder -eq $scriptfolder -and $contentcount -lt 10) { } elseif ($punkfolder -eq $scriptfolder -and $contentcount -lt 10) {
#treat as empty if we have only a few files matching script root name #treat as empty if we have only a few files matching script root name
$scriptlike = get-childitem -Path $punkfolder | Where-Object {$_.name -like "${scriptroot}.*"} $scriptlike = get-childitem -Path $punkfolder | Where-Object {$_.name -like "${scriptroot}.*"}
if ($scriptlike.Count -eq $contentcount) { if ($scriptlike.Count -eq $contentcount) {
$effectively_empty = 1 $effectively_empty = 1
} }
} }
if (-not($effectively_empty)) { if (-not($effectively_empty)) {
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { 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 "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." Write-Host "Please place this script in an empty folder which is to be the punkshell base folder."
exit exit
} else { } else {
$repo_origin = git remote get-url origin $repo_origin = git remote get-url origin
if ($repo_origin -ne $git_upstream) { if ($repo_origin -ne $git_upstream) {
Write-Host "The current repository origin '$repo_origin' is not the expected upstream '${git_upstream}'" Write-Host "The current repository origin '$repo_origin' is not the expected upstream '${git_upstream}'"
$answer = Read-Host "Continue anyway? (Y|N)" $answer = Read-Host "Continue anyway? (Y|N)"
if (-not($answer -match "y")) { if (-not($answer -match "y")) {
exit 1 exit 1
} }
} }
} }
} else { } else {
#punkfolder is empty, or has just the current script #punkfolder is empty, or has just the current script
} }
Set-Location -Path $punkfolder Set-Location -Path $punkfolder
if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) { if (-not(Test-Path -Path (Join-Path -Path $punkfolder -ChildPath ".git") -PathType Container)) {
git init git init
git remote add origin $git_upstream git remote add origin $git_upstream
} }
git fetch origin git fetch origin
if (($launchdir.Path) -eq ($scriptfolder.Path)) { if (($launchdir.Path) -eq ($scriptfolder.Path)) {
if (Test-Path -Path "${scriptroot}.cmd") { if (Test-Path -Path "${scriptroot}.cmd") {
#rename-item won't allow overwriting existing target file #Rename-Item won't allow overwriting existing target file
Move-Item -Path "${scriptroot}.cmd" -Destination "${scriptroot}.cmd.lastrun" -Force Move-Item -Path "${scriptroot}.cmd" -Destination "${scriptroot}.cmd.lastrun" -Force
} }
} }
git pull $git_upstream master git pull $git_upstream master
git checkout "${scriptroot}.cmd" git checkout "${scriptroot}.cmd"
git branch --set-upstream-to=origin/master master git branch --set-upstream-to=origin/master master
Set-Location $launchdir #restore original CWD Set-Location $launchdir #restore original CWD
#see also: https://github.com/jdhitsolutions/WTToolbox #see also: https://github.com/jdhitsolutions/WTToolbox
# Define the necessary Win32 API functions and constants # Define the necessary Win32 API functions and constants
Add-Type -TypeDefinition @" Add-Type -TypeDefinition @"
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public class WinAPI public class WinAPI
{ {
// Console Input/Output Handles // Console Input/Output Handles
public const int STD_OUTPUT_HANDLE = -11; public const int STD_OUTPUT_HANDLE = -11;
public const uint ENABLE_QUICK_EDIT_MODE = 0x0040; public const uint ENABLE_QUICK_EDIT_MODE = 0x0040;
public const uint ENABLE_EXTENDED_FLAGS = 0x0080; public const uint ENABLE_EXTENDED_FLAGS = 0x0080;
public const uint ENABLE_MOUSE_INPUT = 0x0010; public const uint ENABLE_MOUSE_INPUT = 0x0010;
public const uint ENABLE_WINDOW_INPUT = 0x0008; public const uint ENABLE_WINDOW_INPUT = 0x0008;
public const uint ENABLE_INSERT_MODE = 0x0020; public const uint ENABLE_INSERT_MODE = 0x0020;
public const uint ENABLE_LINE_INPUT = 0x0002; public const uint ENABLE_LINE_INPUT = 0x0002;
public const uint ENABLE_ECHO_INPUT = 0x0004; public const uint ENABLE_ECHO_INPUT = 0x0004;
public const uint ENABLE_PROCESSED_INPUT = 0x0001; public const uint ENABLE_PROCESSED_INPUT = 0x0001;
// Console Modes // Console Modes
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
public const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008; public const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle); public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
} }
"@ "@
# Get the handle to the console output buffer # Get the handle to the console output buffer
$stdoutHandle = [WinAPI]::GetStdHandle([WinAPI]::STD_OUTPUT_HANDLE) $stdoutHandle = [WinAPI]::GetStdHandle([WinAPI]::STD_OUTPUT_HANDLE)
# Get the current console mode # Get the current console mode
[uint32]$currentMode = 0 [uint32]$currentMode = 0
if (![WinAPI]::GetConsoleMode($stdoutHandle, [ref]$currentMode)) { if (![WinAPI]::GetConsoleMode($stdoutHandle, [ref]$currentMode)) {
Write-Error "Failed to get console mode. Error code: $($LAST_ERROR)" Write-Error "Failed to get console mode. Error code: $($LAST_ERROR)"
return return
} }
# Enable virtual terminal processing # Enable virtual terminal processing
$newMode = $currentMode -bor [WinAPI]::ENABLE_VIRTUAL_TERMINAL_PROCESSING $newMode = $currentMode -bor [WinAPI]::ENABLE_VIRTUAL_TERMINAL_PROCESSING
# Set the new console mode # Set the new console mode
if (-not [WinAPI]::SetConsoleMode($stdoutHandle, $newMode)) { if (-not [WinAPI]::SetConsoleMode($stdoutHandle, $newMode)) {
Write-Error "Failed to set console mode. Error code: $($LAST_ERROR)" Write-Error "Failed to set console mode. Error code: $($LAST_ERROR)"
return return
} }
Write-Host "Virtual terminal processing enabled successfully." Write-Host "Virtual terminal processing enabled successfully."
write-host "`e[92m getpunk done `e[m" write-host "`e[92m getpunk done `e[m"

46
src/scriptapps/getpunk_wrap.toml

@ -1,23 +1,23 @@
[application] [application]
template="punk.multishell.cmd" template="punk.multishell.cmd"
as_admin=false as_admin=false
scripts=[ scripts=[
"getpunk.ps1", "getpunk.ps1",
"getpunk.bash" "getpunk.bash"
] ]
default_outputfile="getpunk.cmd" default_outputfile="getpunk.cmd"
default_nextshellpath="/usr/bin/env bash" default_nextshellpath="/usr/bin/env bash"
default_nextshelltype="bash" default_nextshelltype="bash"
#valid nextshelltype entries are: tcl perl powershell bash. #valid nextshelltype entries are: tcl perl powershell bash.
#nextshellpath entries must be 128 characters or less. #nextshellpath entries must be 128 characters or less.
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" #win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File"
#win32.nextshelltype="pwsh" #win32.nextshelltype="pwsh"
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy ByPass -File" win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy ByPass -File"
win32.nextshelltype="powershell" win32.nextshelltype="powershell"
win32.outputfile="getpunk.cmd" win32.outputfile="getpunk.cmd"

832
src/scriptapps/runtime.ps1

@ -1,416 +1,416 @@
function GetDynamicParamDictionary { function GetDynamicParamDictionary {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(ValueFromPipeline=$true, Mandatory=$true)] [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[string] $CommandName [string] $CommandName
) )
begin { begin {
# Get a list of params that should be ignored (they're common to all advanced functions) # 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]) | $CommonParameterNames = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([type] [System.Management.Automation.Internal.CommonParameters]) |
Get-Member -MemberType Properties | Get-Member -MemberType Properties |
Select-Object -ExpandProperty Name Select-Object -ExpandProperty Name
} }
process { process {
# Create the dictionary that this scriptblock will return: # Create the dictionary that this scriptblock will return:
$DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
# Convert to object array and get rid of Common params: # Convert to object array and get rid of Common params:
(Get-Command $CommandName | Select-Object -exp Parameters).GetEnumerator() | (Get-Command $CommandName | Select-Object -exp Parameters).GetEnumerator() |
Where-Object { $CommonParameterNames -notcontains $_.Key } | Where-Object { $CommonParameterNames -notcontains $_.Key } |
ForEach-Object { ForEach-Object {
$DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter ( $DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter (
$_.Key, $_.Key,
$_.Value.ParameterType, $_.Value.ParameterType,
$_.Value.Attributes $_.Value.Attributes
) )
$DynParamDictionary.Add($_.Key, $DynamicParameter) $DynParamDictionary.Add($_.Key, $DynamicParameter)
} }
# Return the dynamic parameters # Return the dynamic parameters
return $DynParamDictionary return $DynParamDictionary
} }
} }
function ParameterDefinitions { function ParameterDefinitions {
param( param(
[Parameter(ValueFromRemainingArguments=$true,Position = 1)][string[]] $opts [Parameter(ValueFromRemainingArguments=$true,Position = 1)][string[]] $opts
) )
} }
function psmain { function psmain {
[CmdletBinding()] [CmdletBinding()]
#Empty param block (extra params can be added) #Empty param block (extra params can be added)
param( param(
[Parameter(Mandatory=$false, Position = 0)][string] $action = "" [Parameter(Mandatory=$false, Position = 0)][string] $action = ""
) )
dynamicparam { dynamicparam {
if ($action -eq 'list') { if ($action -eq 'list') {
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "listruntime" ParameterSetName = "listruntime"
Mandatory = $false Mandatory = $false
} }
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$attributeCollection.Add($parameterAttribute) $attributeCollection.Add($parameterAttribute)
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'remote', [switch], $attributeCollection 'remote', [switch], $attributeCollection
) )
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('remote', $dynParam1) $paramDictionary.Add('remote', $dynParam1)
return $paramDictionary return $paramDictionary
} elseif ($action -eq 'fetch') { } elseif ($action -eq 'fetch') {
#GetDynamicParamDictionary ParameterDefinitions #GetDynamicParamDictionary ParameterDefinitions
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "fetchruntime" ParameterSetName = "fetchruntime"
Mandatory = $false Mandatory = $false
Position = 1 Position = 1
} }
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$attributeCollection.Add($parameterAttribute) $attributeCollection.Add($parameterAttribute)
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'runtime', [string], $attributeCollection 'runtime', [string], $attributeCollection
) )
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('runtime', $dynParam1) $paramDictionary.Add('runtime', $dynParam1)
return $paramDictionary return $paramDictionary
} elseif ($action -eq 'run') { } elseif ($action -eq 'run') {
#GetDynamicParamDictionary ParameterDefinitions #GetDynamicParamDictionary ParameterDefinitions
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "runargs" ParameterSetName = "runargs"
Mandatory = $false Mandatory = $false
ValueFromRemainingArguments = $true ValueFromRemainingArguments = $true
} }
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$attributeCollection.Add($parameterAttribute) $attributeCollection.Add($parameterAttribute)
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'opts', [string[]], $attributeCollection 'opts', [string[]], $attributeCollection
) )
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('opts', $dynParam1) $paramDictionary.Add('opts', $dynParam1)
return $paramDictionary return $paramDictionary
} else { } else {
#accept all args when action is unrecognised - so we can go to help anyway #accept all args when action is unrecognised - so we can go to help anyway
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "invalidaction" ParameterSetName = "invalidaction"
Mandatory = $false Mandatory = $false
ValueFromRemainingArguments = $true ValueFromRemainingArguments = $true
} }
$attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$attributeCollection.Add($parameterAttribute) $attributeCollection.Add($parameterAttribute)
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'opts', [string[]], $attributeCollection 'opts', [string[]], $attributeCollection
) )
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('opts', $dynParam1) $paramDictionary.Add('opts', $dynParam1)
return $paramDictionary return $paramDictionary
} }
} }
process { process {
#Called once - we get a single item being our PSBoundParameters dictionary #Called once - we get a single item being our PSBoundParameters dictionary
#write-host "Bound Parameters:$($PSBoundParameters.Keys)" #write-host "Bound Parameters:$($PSBoundParameters.Keys)"
switch ($PSBoundParameters.keys) { switch ($PSBoundParameters.keys) {
'action' { 'action' {
write-host "got action " $PSBoundParameters.action write-host "got action " $PSBoundParameters.action
Set-Variable -Name $_ -Value $PSBoundParameters."$_" Set-Variable -Name $_ -Value $PSBoundParameters."$_"
$known_actions = @("fetch", "list", "run") $known_actions = @("fetch", "list", "run")
if (-not($known_actions -contains $action)) { if (-not($known_actions -contains $action)) {
write-host "fetch '$action' not understood. Known_actions: $known_actions" write-host "fetch '$action' not understood. Known_actions: $known_actions"
exit 1 exit 1
} }
} }
'opts' { 'opts' {
# write-warning "Unused parameters: $($PSBoundParameters.$_)" # write-warning "Unused parameters: $($PSBoundParameters.$_)"
} }
Default { Default {
# write-warning "Unhandled parameter -> [$($_)]" # write-warning "Unhandled parameter -> [$($_)]"
} }
} }
#foreach ($boundparam in $PSBoundParameters.Keys) { #foreach ($boundparam in $PSBoundParameters.Keys) {
# write-host "k: $boundparam" # write-host "k: $boundparam"
#} #}
} }
end { end {
# PSBoundParameters # PSBoundParameters
#write-host "action:'$action'" #write-host "action:'$action'"
$outbase = $PSScriptRoot $outbase = $PSScriptRoot
$outbase = Resolve-Path -Path $outbase $outbase = Resolve-Path -Path $outbase
#expected script location is the bin folder of a punk project #expected script location is the bin folder of a punk project
$rtfolder = Join-Path -Path $outbase -ChildPath "runtime" $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?) #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" $artifacturl = "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master"
switch ($action) { switch ($action) {
'fetch' { 'fetch' {
$arch = "win32-x86_64" $arch = "win32-x86_64"
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" $archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$archurl = "$artifacturl/$arch" $archurl = "$artifacturl/$arch"
$sha1url = "$archurl/sha1sums.txt" $sha1url = "$archurl/sha1sums.txt"
$runtime = "tclsh902z.exe" $runtime = "tclsh902z.exe"
foreach ($boundparam in $PSBoundParameters.Keys) { foreach ($boundparam in $PSBoundParameters.Keys) {
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])" write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])"
} }
if ( $PSBoundParameters["runtime"].Length ) { if ( $PSBoundParameters["runtime"].Length ) {
$runtime = $PSBoundParameters["runtime"] $runtime = $PSBoundParameters["runtime"]
} }
$fileurl = "$archurl/$runtime" $fileurl = "$archurl/$runtime"
$output = join-path -Path $archfolder -ChildPath $runtime $output = join-path -Path $archfolder -ChildPath $runtime
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" $sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt"
$container = split-path -Path $output -Parent $container = split-path -Path $output -Parent
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present
try { try {
Write-Host "Fetching $sha1url" Write-Host "Fetching $sha1url"
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop
Write-Host "sha1 saved at $sha1local" Write-Host "sha1 saved at $sha1local"
} catch { } catch {
Write-Host "An error occurred while downloading ${sha1url}: $($_.Exception.Message)" Write-Host "An error occurred while downloading ${sha1url}: $($_.Exception.Message)"
if ($_.Exception.Response) { if ($_.Exception.Response) {
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)"
} }
} }
if (Test-Path -Path $sha1local -PathType Leaf) { if (Test-Path -Path $sha1local -PathType Leaf) {
$sha1Content = Get-Content -Path $sha1local $sha1Content = Get-Content -Path $sha1local
$stored_sha1 = "" $stored_sha1 = ""
foreach ($line in $sha1Content) { foreach ($line in $sha1Content) {
#all sha1sums have * (binary indicator) - review #all sha1sums have * (binary indicator) - review
$match = [regex]::Match($line,"(.*) [*]${runtime}$") $match = [regex]::Match($line,"(.*) [*]${runtime}$")
if ($match.Success) { if ($match.Success) {
$stored_sha1 = $match.Groups[1].Value $stored_sha1 = $match.Groups[1].Value
Write-host "stored hash from sha1sums.txt: $storedhash" Write-host "stored hash from sha1sums.txt: $storedhash"
break break
} }
} }
if ($stored_sha1 -eq "") { if ($stored_sha1 -eq "") {
Write-Host "Unable to locate hash for $runtime in $sha1local - Aborting" Write-Host "Unable to locate hash for $runtime in $sha1local - Aborting"
Write-Host "Please download and verify manually" Write-Host "Please download and verify manually"
return return
} }
$need_download = $false $need_download = $false
if (Test-Path -Path $output -PathType Leaf) { if (Test-Path -Path $output -PathType Leaf) {
Write-Host "Runtime already found at $output" Write-Host "Runtime already found at $output"
Write-Host "Checking sha1 checksum of local file versus sha1 of server file" Write-Host "Checking sha1 checksum of local file versus sha1 of server file"
$file_sha1 = Get-FileHash -Path "$output" -Algorithm SHA1 $file_sha1 = Get-FileHash -Path "$output" -Algorithm SHA1
if (${file_sha1}.Hash -ne $stored_sha1) { if (${file_sha1}.Hash -ne $stored_sha1) {
Write-Host "$runtime on server has different sha1 hash - Download required" Write-Host "$runtime on server has different sha1 hash - Download required"
$need_download = $true $need_download = $true
} }
} else { } else {
Write-Host "$runtime not found locally - Download required" Write-Host "$runtime not found locally - Download required"
$need_download = $true $need_download = $true
} }
if ($need_download) { if ($need_download) {
Write-Host "Downloading from $fileurl ..." Write-Host "Downloading from $fileurl ..."
try { try {
Invoke-WebRequest -Uri $fileurl -OutFile "${output}.tmp" -ErrorAction Stop Invoke-WebRequest -Uri $fileurl -OutFile "${output}.tmp" -ErrorAction Stop
Write-Host "Runtime saved at $output.tmp" Write-Host "Runtime saved at $output.tmp"
} }
catch { catch {
Write-Host "An error occurred while downloading $fileurl $($_.Exception.Message)" Write-Host "An error occurred while downloading $fileurl $($_.Exception.Message)"
if ($_.Exception.Response) { if ($_.Exception.Response) {
Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)" Write-Host "HTTP Status code: $($_.Exception.Response.StatusCode)"
} }
return return
} }
Write-Host "comparing sha1 checksum of downloaded file with data in sha1sums.txt" 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?) 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 $newfile_sha1 = Get-FileHash -Path "${output}.tmp" -Algorithm SHA1
if (${newfile_sha1}.Hash -eq $stored_sha1) { if (${newfile_sha1}.Hash -eq $stored_sha1) {
Write-Host "sha1 checksum ok" Write-Host "sha1 checksum ok"
Move-Item -Path "${output}.tmp" -Destination "${output}" -Force Move-Item -Path "${output}.tmp" -Destination "${output}" -Force
Write-Host "Runtime is available at ${output}" Write-Host "Runtime is available at ${output}"
} else { } else {
Write-Host "WARNING! sha1 of downloaded file at $output.tmp does not match stored sha1 from sha1sums.txt" Write-Host "WARNING! sha1 of downloaded file at $output.tmp does not match stored sha1 from sha1sums.txt"
return return
} }
} else { } else {
Write-Host "Local copy of runtime at $output seems to match sha1 checksum of file on server." Write-Host "Local copy of runtime at $output seems to match sha1 checksum of file on server."
Write-Host "No download required" Write-Host "No download required"
} }
} else { } else {
Write-Host "Unable to consult local copy of sha1sums.txt at $sha1local" Write-Host "Unable to consult local copy of sha1sums.txt at $sha1local"
if (Test-Path -Path $output -PathType Leaf) { 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 "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." Write-Host "Unable to check for updated version at this time."
} else { } else {
Write-Host "Please retry - or manually download a runtime from $archurl and verify checksums" Write-Host "Please retry - or manually download a runtime from $archurl and verify checksums"
} }
} }
} }
'run' { 'run' {
#select first (or configured default) runtime and launch, passing arguments #select first (or configured default) runtime and launch, passing arguments
$arch = "win32-x86_64" $arch = "win32-x86_64"
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" $archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
if (-not(Test-Path -Path $archfolder -PathType Container)) { 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" write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install"
} else { } else {
$dircontents = (get-childItem -Path $archfolder -File | Sort-Object Name) $dircontents = (get-childItem -Path $archfolder -File | Sort-Object Name)
if ($dircontents.Count -gt 0) { if ($dircontents.Count -gt 0) {
#write-host "run.." #write-host "run.."
write-host "num params: $($PSBoundParameters.opts.count)" write-host "num params: $($PSBoundParameters.opts.count)"
#todo - use 'active' runtime - need to lookup (PSToml?) #todo - use 'active' runtime - need to lookup (PSToml?)
#when no 'active' runtime for this os-arch - use last item (sorted in dictionary order) #when no 'active' runtime for this os-arch - use last item (sorted in dictionary order)
$active = $dircontents[-1].FullName $active = $dircontents[-1].FullName
write-host "using: $active" write-host "using: $active"
if ($PSBoundParameters.opts.Length -gt 0) { if ($PSBoundParameters.opts.Length -gt 0) {
$optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null $optsType = $PSBoundParameters.opts.GetType() #method can only be called if .opts is not null
write-host "type of opts: $($optsType.FullName)" write-host "type of opts: $($optsType.FullName)"
foreach ($boundparam in $PSBoundParameters.opts) { foreach ($boundparam in $PSBoundParameters.opts) {
write-host $boundparam write-host $boundparam
} }
Write-Host "opts: $($PSBoundParameters.opts)" Write-Host "opts: $($PSBoundParameters.opts)"
Write-Host "args: $args" Write-Host "args: $args"
Write-HOst "argscount: $($args.Count)" Write-HOst "argscount: $($args.Count)"
$arglist = @() $arglist = @()
foreach ($o in $PSBoundParameters.opts) { foreach ($o in $PSBoundParameters.opts) {
$oquoted = $o -replace '"', "`\`"" $oquoted = $o -replace '"', "`\`""
#$oquoted = $oquoted -replace "'", "`'" #$oquoted = $oquoted -replace "'", "`'"
if ($oquoted -match "\s") { if ($oquoted -match "\s") {
$oquoted = "`"$oquoted`"" $oquoted = "`"$oquoted`""
} }
$arglist += @($oquoted) $arglist += @($oquoted)
} }
$arglist = $arglist.TrimEnd(' ') $arglist = $arglist.TrimEnd(' ')
write-host "arglist: $arglist" write-host "arglist: $arglist"
#$arglist = $PSBoundParameters.opts #$arglist = $PSBoundParameters.opts
Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait
} else { } else {
#powershell 5.1 and earlier can't accept an empty -ArgumentList value :/ !! #powershell 5.1 and earlier can't accept an empty -ArgumentList value :/ !!
#$arglist = @() #$arglist = @()
#Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait #Start-Process -FilePath $active -ArgumentList $arglist -NoNewWindow -Wait
#Start-Process -FilePath $active -ArgumentList "" -NoNewWindow -Wait #Start-Process -FilePath $active -ArgumentList "" -NoNewWindow -Wait
Start-Process -FilePath $active -NoNewWindow -Wait Start-Process -FilePath $active -NoNewWindow -Wait
} }
} else { } else {
write-host "No files found in $archfolder" write-host "No files found in $archfolder"
write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install." write-host "No runtimes seem to be installed for $arch`nPlease use 'runtime.cmd fetch' to install."
} }
} }
} }
'list' { 'list' {
#todo - option to list for other os-arch #todo - option to list for other os-arch
$arch = 'win32-x86_64' $arch = 'win32-x86_64'
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch" $archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt" $sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt"
$archurl = "$artifacturl/$arch" $archurl = "$artifacturl/$arch"
$sha1url = "$archurl/sha1sums.txt" $sha1url = "$archurl/sha1sums.txt"
if ( $PSBoundParameters.ContainsKey('remote') ) { if ( $PSBoundParameters.ContainsKey('remote') ) {
if (-not (test-path -Path $archfolder -Type Container)) { if (-not (test-path -Path $archfolder -Type Container)) {
new-item -Path $container -ItemType Directory -force #create with intermediary folders if not already present 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 "Checking for available remote runtimes for"
Write-Host "Fetching $sha1url" Write-Host "Fetching $sha1url"
Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop Invoke-WebRequest -Uri $sha1url -OutFile $sha1local -ErrorAction Stop
Write-Host "sha1 saved at $sha1local" Write-Host "sha1 saved at $sha1local"
$sha1Content = Get-Content -Path $sha1local $sha1Content = Get-Content -Path $sha1local
$remotedict = @{} $remotedict = @{}
foreach ($line in $sha1Content) { foreach ($line in $sha1Content) {
#all sha1sums have * (binary indicator) - review #all sha1sums have * (binary indicator) - review
$match = [regex]::Match($line,"(.*) [*](.*)$") $match = [regex]::Match($line,"(.*) [*](.*)$")
if ($match.Success) { if ($match.Success) {
$server_sha1 = $match.Groups[1].Value $server_sha1 = $match.Groups[1].Value
$server_rt = $match.Groups[2].Value $server_rt = $match.Groups[2].Value
$remotedict[$server_rt] = $server_sha1 $remotedict[$server_rt] = $server_sha1
} }
} }
$localdict = @{} $localdict = @{}
if (test-path -Path $archfolder -Type Container) { if (test-path -Path $archfolder -Type Container) {
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) $dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) })
foreach ($f in $dircontents) { foreach ($f in $dircontents) {
$local_sha1 = Get-FileHash -Path $(${f}.FullName) -Algorithm SHA1 $local_sha1 = Get-FileHash -Path $(${f}.FullName) -Algorithm SHA1
$localdict[$f.Name] = ${local_sha1}.Hash $localdict[$f.Name] = ${local_sha1}.Hash
} }
} }
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
Write-host "Runtimes for $arch" Write-host "Runtimes for $arch"
Write-host "Local $archfolder" Write-host "Local $archfolder"
Write-host "Remote $archurl" Write-host "Remote $archurl"
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
Write-host "Local Remote" Write-host "Local Remote"
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
# 12345678910234567892023456789302345 # 12345678910234567892023456789302345
$G = "`e[32m" #Green $G = "`e[32m" #Green
$Y = "`e[33m" #Yellow $Y = "`e[33m" #Yellow
$R = "`e[31m" #Red $R = "`e[31m" #Red
$RST = "`e[m" $RST = "`e[m"
foreach ($key in $localdict.Keys) { foreach ($key in $localdict.Keys) {
$local_sha1 = $($localdict[$key]) $local_sha1 = $($localdict[$key])
if ($remotedict.ContainsKey($key)) { if ($remotedict.ContainsKey($key)) {
if ($local_sha1 -eq $remotedict[$key]) { if ($local_sha1 -eq $remotedict[$key]) {
$rhs = "Same version" $rhs = "Same version"
$C = $G $C = $G
} else { } else {
$rhs = "UPDATE AVAILABLE" $rhs = "UPDATE AVAILABLE"
$C = $Y $C = $Y
} }
} else { } else {
$C = $R $C = $R
$rhs = "(not listed on server)" $rhs = "(not listed on server)"
} }
#ansi problems from cmd.exe not in windows terminal - review #ansi problems from cmd.exe not in windows terminal - review
$C = "" $C = ""
$RST = "" $RST = ""
$lhs = "$key".PadRight(35, ' ') $lhs = "$key".PadRight(35, ' ')
write-host -nonewline "${C}${lhs}${RST}" write-host -nonewline "${C}${lhs}${RST}"
write-host $rhs write-host $rhs
} }
$lhs_missing = "-".PadRight(35, ' ') $lhs_missing = "-".PadRight(35, ' ')
foreach ($key in $remotedict.Keys) { foreach ($key in $remotedict.Keys) {
if (-not ($localdict.ContainsKey($key))) { if (-not ($localdict.ContainsKey($key))) {
write-host -nonewline $lhs_missing write-host -nonewline $lhs_missing
write-host $key write-host $key
} }
} }
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
} else { } else {
if (test-path -Path $archfolder -Type Container) { if (test-path -Path $archfolder -Type Container) {
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
Write-Host "Local runtimes for $arch" Write-Host "Local runtimes for $arch"
$dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) }) $dircontents = (get-childItem -Path $archfolder -File | Where-object {-not ($(".txt",".tm") -contains $_.Extension) })
write-host "$(${dircontents}.count) files in $archfolder" write-host "$(${dircontents}.count) files in $archfolder"
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
foreach ($f in $dircontents) { foreach ($f in $dircontents) {
write-host $f.Name write-host $f.Name
} }
Write-host "-----------------------------------------------------------------------" Write-host "-----------------------------------------------------------------------"
Write-host "Use: 'list -remote' to compare local runtimes with those available on the artifact server" Write-host "Use: 'list -remote' to compare local runtimes with those available on the artifact server"
} else { } else {
write-host "No runtimes seem to be installed for $arch in $archfolder`nPlease use 'runtime.cmd fetch' to install." 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" write-host "Use 'runtime.cmd list -remote' to see available runtimes for $arch"
} }
} }
} }
default { default {
$actions = @("fetch", "list", "run") $actions = @("fetch", "list", "run")
write-host "Available actions: $actions" write-host "Available actions: $actions"
write-host "received" write-host "received"
foreach ($boundparam in $PSBoundParameters.opts) { foreach ($boundparam in $PSBoundParameters.opts) {
write-host $boundparam write-host $boundparam
} }
} }
} }
return $PSBoundParameters return $PSBoundParameters
} }
} }
#write-host (psmain @args) #write-host (psmain @args)
#$returnvalue = psmain @args #$returnvalue = psmain @args
#Write-Host "Function Returned $returnvalue" -ForegroundColor Cyan #Write-Host "Function Returned $returnvalue" -ForegroundColor Cyan
#return $returnvalue #return $returnvalue
psmain @args | out-null psmain @args | out-null
exit 0 exit 0

54
src/scriptapps/runtime_wrap.toml

@ -1,27 +1,27 @@
[application] [application]
template="punk.multishell.cmd" template="punk.multishell.cmd"
as_admin=false as_admin=false
scripts=[ scripts=[
"runtime.ps1", "runtime.ps1",
"runtime.bash" "runtime.bash"
] ]
default_outputfile="runtime.cmd" default_outputfile="runtime.cmd"
default_nextshellpath="/usr/bin/env bash" default_nextshellpath="/usr/bin/env bash"
default_nextshelltype="bash" default_nextshelltype="bash"
#valid nextshelltype entries are: tcl perl powershell bash. #valid nextshelltype entries are: tcl perl powershell bash.
#nextshellpath entries must be 64 characters or less. #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 #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) #do use -File (even though pwsh doesn't require it)
#win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File" #win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -File"
#win32.nextshelltype="pwsh" #win32.nextshelltype="pwsh"
#powershell needs cmd.exe to preserve spaced args #powershell needs cmd.exe to preserve spaced args
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File" win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File"
win32.nextshelltype="powershell" win32.nextshelltype="powershell"
win32.outputfile="runtime.cmd" win32.outputfile="runtime.cmd"

Loading…
Cancel
Save