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