9 changed files with 1678 additions and 44 deletions
@ -0,0 +1,289 @@
|
||||
# -*- tcl -*- |
||||
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from <pkg>-buildversion.txt |
||||
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm |
||||
# |
||||
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. |
||||
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
# (C) 2025 |
||||
# |
||||
# @@ Meta Begin |
||||
# Application punk::ubl 999999.0a1.0 |
||||
# Meta platform tcl |
||||
# Meta license MIT |
||||
# @@ Meta End |
||||
|
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
# doctools header |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
#*** !doctools |
||||
#[manpage_begin shellspy_module_punk::ubl 0 999999.0a1.0] |
||||
#[copyright "2025"] |
||||
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}] |
||||
#[moddesc {-}] [comment {-- Description at end of page heading --}] |
||||
#[require punk::ubl] |
||||
#[keywords module] |
||||
#[description] |
||||
#[para] Basic UBL |
||||
#[para] https://docs.oasis-open.org/ubl/os-UBL-2.4/ |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
#*** !doctools |
||||
#[section Overview] |
||||
#[para] overview of punk::ubl |
||||
#[subsection Concepts] |
||||
#[para] - |
||||
|
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
## Requirements |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
#*** !doctools |
||||
#[subsection dependencies] |
||||
#[para] packages used by punk::ubl |
||||
#[list_begin itemized] |
||||
|
||||
package require Tcl 8.6- |
||||
#*** !doctools |
||||
#[item] [package {Tcl 8.6}] |
||||
|
||||
# #package require frobz |
||||
# #*** !doctools |
||||
# #[item] [package {frobz}] |
||||
|
||||
#*** !doctools |
||||
#[list_end] |
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
#*** !doctools |
||||
#[section API] |
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
# oo::class namespace |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
#tcl::namespace::eval punk::ubl::class { |
||||
#*** !doctools |
||||
#[subsection {Namespace punk::ubl::class}] |
||||
#[para] class definitions |
||||
#if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} { |
||||
#*** !doctools |
||||
#[list_begin enumerated] |
||||
|
||||
# oo::class create interface_sample1 { |
||||
# #*** !doctools |
||||
# #[enum] CLASS [class interface_sample1] |
||||
# #[list_begin definitions] |
||||
|
||||
# method test {arg1} { |
||||
# #*** !doctools |
||||
# #[call class::interface_sample1 [method test] [arg arg1]] |
||||
# #[para] test method |
||||
# puts "test: $arg1" |
||||
# } |
||||
|
||||
# #*** !doctools |
||||
# #[list_end] [comment {-- end definitions interface_sample1}] |
||||
# } |
||||
|
||||
#*** !doctools |
||||
#[list_end] [comment {--- end class enumeration ---}] |
||||
#} |
||||
#} |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
|
||||
|
||||
tcl::namespace::eval punk::ubl { |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
# Base namespace |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
#*** !doctools |
||||
#[subsection {Namespace punk::ubl}] |
||||
#[para] Core API functions for punk::ubl |
||||
#[list_begin definitions] |
||||
|
||||
variable PUNKARGS |
||||
|
||||
|
||||
|
||||
|
||||
#proc sample1 {p1 n args} { |
||||
# #*** !doctools |
||||
# #[call [fun sample1] [arg p1] [arg n] [opt {option value...}]] |
||||
# #[para]Description of sample1 |
||||
# #[para] Arguments: |
||||
# # [list_begin arguments] |
||||
# # [arg_def tring p1] A description of string argument p1. |
||||
# # [arg_def integer n] A description of integer argument n. |
||||
# # [list_end] |
||||
# return "ok" |
||||
#} |
||||
|
||||
|
||||
|
||||
|
||||
#*** !doctools |
||||
#[list_end] [comment {--- end definitions namespace punk::ubl ---}] |
||||
} |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
# Secondary API namespace |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
tcl::namespace::eval punk::ubl::lib { |
||||
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase |
||||
tcl::namespace::path [tcl::namespace::parent] |
||||
#*** !doctools |
||||
#[subsection {Namespace punk::ubl::lib}] |
||||
#[para] Secondary functions that are part of the API |
||||
#[list_begin definitions] |
||||
|
||||
#proc utility1 {p1 args} { |
||||
# #*** !doctools |
||||
# #[call lib::[fun utility1] [arg p1] [opt {?option value...?}]] |
||||
# #[para]Description of utility1 |
||||
# return 1 |
||||
#} |
||||
|
||||
|
||||
|
||||
#*** !doctools |
||||
#[list_end] [comment {--- end definitions namespace punk::ubl::lib ---}] |
||||
} |
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
|
||||
|
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
#*** !doctools |
||||
#[section Internal] |
||||
#tcl::namespace::eval punk::ubl::system { |
||||
#*** !doctools |
||||
#[subsection {Namespace punk::ubl::system}] |
||||
#[para] Internal functions that are not part of the API |
||||
|
||||
|
||||
|
||||
#} |
||||
|
||||
|
||||
# == === === === === === === === === === === === === === === |
||||
# Sample 'about' function with punk::args documentation |
||||
# == === === === === === === === === === === === === === === |
||||
tcl::namespace::eval punk::ubl { |
||||
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase |
||||
variable PUNKARGS |
||||
variable PUNKARGS_aliases |
||||
|
||||
lappend PUNKARGS [list { |
||||
@id -id "(package)punk::ubl" |
||||
@package -name "punk::ubl" -help\ |
||||
"Package |
||||
Description" |
||||
}] |
||||
|
||||
namespace eval argdoc { |
||||
#namespace for custom argument documentation |
||||
proc package_name {} { |
||||
return punk::ubl |
||||
} |
||||
proc about_topics {} { |
||||
#info commands results are returned in an arbitrary order (like array keys) |
||||
set topic_funs [info commands [namespace current]::get_topic_*] |
||||
set about_topics [list] |
||||
foreach f $topic_funs { |
||||
set tail [namespace tail $f] |
||||
lappend about_topics [string range $tail [string length get_topic_] end] |
||||
} |
||||
#Adjust this function or 'default_topics' if a different order is required |
||||
return [lsort $about_topics] |
||||
} |
||||
proc default_topics {} {return [list Description *]} |
||||
|
||||
# ------------------------------------------------------------- |
||||
# get_topic_ functions add more to auto-include in about topics |
||||
# ------------------------------------------------------------- |
||||
proc get_topic_Description {} { |
||||
punk::args::lib::tstr [string trim { |
||||
package punk::ubl |
||||
description to come.. |
||||
} \n] |
||||
} |
||||
proc get_topic_License {} { |
||||
return "MIT" |
||||
} |
||||
proc get_topic_Version {} { |
||||
return "$::punk::ubl::version" |
||||
} |
||||
proc get_topic_Contributors {} { |
||||
set authors {{Julian Noble <julian@precisium.com.au>}} |
||||
set contributors "" |
||||
foreach a $authors { |
||||
append contributors $a \n |
||||
} |
||||
if {[string index $contributors end] eq "\n"} { |
||||
set contributors [string range $contributors 0 end-1] |
||||
} |
||||
return $contributors |
||||
} |
||||
proc get_topic_custom-topic {} { |
||||
punk::args::lib::tstr -return string { |
||||
A custom |
||||
topic |
||||
etc |
||||
} |
||||
} |
||||
# ------------------------------------------------------------- |
||||
} |
||||
|
||||
# we re-use the argument definition from punk::args::standard_about and override some items |
||||
set overrides [dict create] |
||||
dict set overrides @id -id "::punk::ubl::about" |
||||
dict set overrides @cmd -name "punk::ubl::about" |
||||
dict set overrides @cmd -help [string trim [punk::args::lib::tstr { |
||||
About punk::ubl |
||||
}] \n] |
||||
dict set overrides topic -choices [list {*}[punk::ubl::argdoc::about_topics] *] |
||||
dict set overrides topic -choicerestricted 1 |
||||
dict set overrides topic -default [punk::ubl::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict |
||||
set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *] |
||||
lappend PUNKARGS [list $newdef] |
||||
proc about {args} { |
||||
package require punk::args |
||||
#standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on |
||||
set argd [punk::args::parse $args withid ::punk::ubl::about] |
||||
lassign [dict values $argd] _leaders opts values _received |
||||
punk::args::package::standard_about -package_about_namespace ::punk::ubl::argdoc {*}$opts {*}[dict get $values topic] |
||||
} |
||||
} |
||||
# end of sample 'about' function |
||||
# == === === === === === === === === === === === === === === |
||||
|
||||
|
||||
# ----------------------------------------------------------------------------- |
||||
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked |
||||
# ----------------------------------------------------------------------------- |
||||
# variable PUNKARGS |
||||
# variable PUNKARGS_aliases |
||||
namespace eval ::punk::args::register { |
||||
#use fully qualified so 8.6 doesn't find existing var in global namespace |
||||
lappend ::punk::args::register::NAMESPACES ::punk::ubl |
||||
} |
||||
# ----------------------------------------------------------------------------- |
||||
|
||||
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
||||
## Ready |
||||
package provide punk::ubl [tcl::namespace::eval punk::ubl { |
||||
variable pkg punk::ubl |
||||
variable version |
||||
set version 999999.0a1.0 |
||||
}] |
||||
return |
||||
|
||||
#*** !doctools |
||||
#[manpage_end] |
||||
|
@ -0,0 +1,3 @@
|
||||
0.1.0 |
||||
#First line must be a semantic version number |
||||
#all other lines are ignored. |
@ -0,0 +1,15 @@
|
||||
#mkdir -p ./zig |
||||
|
||||
#tarball="zig-x86_64-windows-0.15.1.zip" |
||||
#tarball="zig-x86_64-freebsd-0.15.1.tar.xz" |
||||
tarball="zig-x86_64-linux-0.15.1.tar.xz" |
||||
|
||||
automation_name="punkshell+julian@precisium.com.au_target_by_latency" |
||||
uristring="https://ziglang.org" |
||||
full_uristring="${uristring}/download/0.15.1/${tarball}?source=${automation_name}" |
||||
echo "Unimplemented: Download from ${full_uristring} and extract manually" |
||||
#wget $full_uristring -O ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
#tar -xf ./zig/zig-linux-x86_64-0.10.1.tar.xz -C ./zig --strip-components=1 |
||||
#rm ./zig/zig-linux-x86_64-0.10.1.tar.xz |
||||
#echo "Zig installed." |
||||
#./zig/zig version |
@ -0,0 +1,186 @@
|
||||
|
||||
#Join-Path using verbose method to support powershell 5? |
||||
#$outbase = Join-Path -Path $PSScriptRoot -ChildPath "../.." |
||||
$outbase = $PSScriptRoot |
||||
$outbase = Resolve-Path -Path $outbase |
||||
$toolsfolder = Join-Path -Path $outbase -ChildPath "tools" |
||||
if (-not(Test-Path -Path $toolsfolder -PathType Container)) { |
||||
#create folder - (can include missing intermediaries) |
||||
New-Item -Path $toolsfolder -ItemType Directory |
||||
} |
||||
$zigfolder = Join-Path $toolsfolder -ChildPath "zig" |
||||
$zigexe = Join-Path $zigfolder "zig.exe" |
||||
$releasearchive = "zig-x86_64-windows-0.15.1.zip" ;#zip on windows, tarball on every other platform |
||||
Write-Output "powershell version: $($PSVersionTable.PSVersion)" |
||||
|
||||
if (Get-Command $zigexe -ErrorAction SilentlyContinue) { |
||||
Write-Host "zig.exe is installed in tools/zig" |
||||
$zigv = tools/zig/zig.exe version 2>&1 |
||||
$stdout = $zigv | Where-Object {$_ -is [string]} |
||||
$stderr = $zigv | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
if ($stderr) { |
||||
Write-Host "Unexpected output from tools/zig/zig.exe: $stderr" |
||||
Write-Host "Consider deleting tools/zig and re-downloading" |
||||
} else { |
||||
Write-Host "tools/zig/zig.exe version is: $stdout" |
||||
} |
||||
exit |
||||
} |
||||
|
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is available" |
||||
} else { |
||||
Write-Host "minisign is missing. Will attempt to install using winget." |
||||
#Find-Module/Install-Module: older mechanism, available in powershell |
||||
#Find-PSResource/Install-PSResource: only available in newer pwsh etc? |
||||
$wgclient = Get-Module -ListAvailable -Name Microsoft.WinGet.Client |
||||
if (${wgclient}.Length -eq 0) { |
||||
Write-Host "Microsoft.WinGet.Client module not installed.. will try to install." |
||||
Install-PackageProvider -Name NuGet -Force |
||||
$psgallery_existing_policy = (Get-PSRepository -Name PSGallery).InstallationPolicy |
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
#Applies to all versions of PowerShell for the user, and is persistent for current user. |
||||
#This has risks in that a powershell session started after this call, and before we reset it, will treat PSGallery as trusted |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted |
||||
} |
||||
Install-Module -Scope CurrentUser -Name Microsoft.Winget.Client -Force -Repository PSGallery |
||||
Repair-WinGetPackageManager |
||||
import-module -name Microsoft.Winget.client |
||||
|
||||
if ($psgallery_existing_policy -eq "Untrusted") { |
||||
Set-PSRepository -Name PSGallery -InstallationPolicy Untrusted |
||||
} |
||||
} else { |
||||
Write-Host "Microsoft.WinGet.Client is available" |
||||
} |
||||
$wingetversion = (Find-WinGetPackage jedisct1.minisign).Version |
||||
if ($wingetversion) { |
||||
Write-Host "Installing minisign version: ${wingetversion}" |
||||
Install-WinGetPackage -Id "jedisct1.minisign" |
||||
} |
||||
if (Get-Command "minisign" -ErrorAction SilentlyContinue) { |
||||
Write-Host "minisign is now available" |
||||
} else { |
||||
Write-Host "minisign is still not available" |
||||
} |
||||
|
||||
exit |
||||
} |
||||
|
||||
$zigpubkey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U" |
||||
$mirrors_url = "https://ziglang.org/download/community-mirrors.txt" |
||||
$mirrors_response = $(Invoke-WebRequest -Uri $mirrors_url) |
||||
if ($mirrors_response.StatusCode -eq 200) { |
||||
$mirror_array = $mirrors_response.Content.TrimEnd("`r`n") -split "`r`n|`n" |
||||
#$mirror_array += "https://bogusxxx.org" #test behaviour of a bogus/down entry |
||||
$mirror_array += "https://ziglang.org" #main site |
||||
|
||||
$dict_mirrors = [ordered]@{} |
||||
$host_list = @() #same ordering as dict_mirrors |
||||
foreach ($mirror in $mirror_array) { |
||||
$uri = New-Object System.Uri($mirror) |
||||
$hostname = $uri.Host |
||||
$dict_mirrors[$hostname] = @{} |
||||
$dict_mirrors[$hostname]["uri"] = $mirror |
||||
$host_list += $hostname |
||||
#write-host "Host name: $hostname" |
||||
} |
||||
#write-host "dict: $($dict_mirrors | out-String)" |
||||
write-host "host_list: $host_list" |
||||
|
||||
$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]) |
||||
} |
||||
$sorted_mirror_dicts = $list_mirror_dicts | Sort-Object -Property Latency |
||||
Write-Host "Sorted by latency: $($sorted_mirror_dicts | Format-Table -AutoSize | Out-String)" |
||||
$automation_name = "punkshell+julian@precisium.com.au_target_by_latency" |
||||
|
||||
foreach ($hostinfo in $sorted_mirror_dicts) { |
||||
$uristring = $hostinfo.uri |
||||
if ($uristring -eq "https://ziglang.org") { |
||||
$full_uristring = "${uristring}/download/0.15.1/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/download/0.15.1/${releasearchive}.minisig?source=${automation_name}" |
||||
} else { |
||||
$full_uristring = "${uristring}/${releasearchive}?source=${automation_name}" |
||||
$sig_uristring = "${uristring}/${releasearchive}.minisig?source=${automation_name}" |
||||
} |
||||
Write-Host "Downloading zig from $full_uristring" |
||||
#$uriobj = [uri]$full_uristring |
||||
#$lastSegment = $uriobj.Segments[-1] |
||||
#$outfile = Join-Path $toolsfolder -ChildPath $lastSegment |
||||
$outfile = Join-Path $toolsfolder -ChildPath $releasearchive |
||||
Write-Host "Download to: $outfile" |
||||
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile |
||||
|
||||
if (-not(Test-Path -Path $outfile -PathType Leaf)) { |
||||
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
Write-Host "Downloading minisig signature from $sig_uristring" |
||||
Invoke-WebRequest -Uri $sig_uristring -Outfile "${outfile}.minisig" |
||||
if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) { |
||||
write-Host "Failed to download minisig from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring" |
||||
continue |
||||
} |
||||
|
||||
write-host "downloaded $outfile and ${outfile}.minisig - validating signature..." |
||||
#validate releasearchive (tarball/zip) |
||||
$sigresult = minisign -V -P $zigpubkey -m $outfile 2>&1 |
||||
$stdout = $sigresult | Where-Object {$_ -is [string]} |
||||
$stderr = $sigresult | Where-Object {$_ -is [System.Management.Automation.ErrorRecord]} |
||||
$is_valid = $false |
||||
if ($stderr) { |
||||
write-host "Signature validation failed with message: $stderr" |
||||
} else { |
||||
if (($stdout | Out-String).Contains("signature verified")) { |
||||
write-host $stdout |
||||
$is_valid = $true |
||||
} else { |
||||
write-host "Unexpected output from minisign: $stdout" |
||||
write-host "Did not contain 'signature verified'" |
||||
} |
||||
} |
||||
if (-not($is_valid)) { |
||||
write-Host "Couldn't verify signature from download site $uristring" |
||||
Remove-Item -Path $outfile -ErrorAction SilentlyContinue |
||||
Remove-Item -Path "${outfile}.minisig" -ErrorAction SilentlyContinue |
||||
continue |
||||
} |
||||
|
||||
Write-Host "Signature OK - extracting archive" |
||||
Expand-Archive -path $outfile -DestinationPath $toolsfolder -Force |
||||
#Remove-Item -Path "$outfile" |
||||
$zip_rootname = [System.IO.Path]::GetFileNameWithoutExtension($releasearchive) |
||||
#Rename-Item -Path |
||||
write-host "zip_rootname: $zip_rootname" |
||||
Rename-Item -Path $(Join-Path -Path $toolsfolder -ChildPath $zip_rootname) -NewName $zigfolder |
||||
Write-Host "Zig installed in ${zigfolder}" |
||||
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" |
||||
$v = Invoke-Expression "$zigexe version" |
||||
Write-Host "ZIG VERSION: ${v}" |
||||
$test_ok = 1 ;#todo |
||||
if ($test_ok) { |
||||
break |
||||
} |
||||
} |
||||
|
||||
} else { |
||||
Write-Host "Unable to retrieve list of zig community mirrors from $mirrors_url" |
||||
} |
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
[application] |
||||
template="punk.multishell.cmd" |
||||
as_admin=false |
||||
|
||||
scripts=[ |
||||
"getzig.ps1", |
||||
"getzig.bash" |
||||
] |
||||
|
||||
default_outputfile="getzig.cmd" |
||||
default_nextshellpath="/usr/bin/env bash" |
||||
default_nextshelltype="bash" |
||||
|
||||
#valid nextshelltype entries are: tcl perl pwsh powershell bash. |
||||
#nextshellpath entries must be 64 characters or less. |
||||
|
||||
win32.nextshellpath="pwsh" |
||||
win32.nextshelltype="pwsh" |
||||
win32.outputfile="getzig.cmd" |
Loading…
Reference in new issue