Browse Source

improved multishell script wrap, fix docs, fix unix launch, etc

master
Julian Noble 12 months ago
parent
commit
a689138a20
  1. 29
      bin/dtplite.bat
  2. 28
      bin/dtplite.tcl
  3. 46
      bin/kettle.bat
  4. 12
      src/bootsupport/include_modules.config
  5. 4
      src/bootsupport/modules/punk/cap-0.1.0.tm
  6. 71
      src/bootsupport/modules/punk/docgen-0.1.0.tm
  7. 153
      src/bootsupport/modules/punk/du-0.1.0.tm
  8. 4
      src/bootsupport/modules/punk/mix/cli-0.3.tm
  9. 7
      src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm
  10. 2
      src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  11. 61
      src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm
  12. 73
      src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm
  13. 4
      src/bootsupport/modules/punk/ns-0.1.0.tm
  14. 397
      src/bootsupport/modules/punk/path-0.1.0.tm
  15. 40
      src/bootsupport/modules/punk/repo-0.1.1.tm
  16. 2
      src/bootsupport/modules/punkcheck-0.1.0.tm
  17. 3
      src/doc/include/changes.inc
  18. 28
      src/doc/include/changes_0.1.inc
  19. 18
      src/doc/include/feedback.inc
  20. 2
      src/doc/include/general.inc
  21. 3
      src/doc/include/punkshell.inc
  22. 2
      src/doc/include/welcome.inc
  23. 15
      src/doc/project_changes.man
  24. 15
      src/doc/project_intro.man
  25. 4
      src/doc/punk/_module_cap-0.1.0.tm.man
  26. 3
      src/doc/punk/_module_path-0.1.0.tm.man
  27. 17
      src/doc/punk/mix/commandset/_module_project-0.1.0.tm.man
  28. 4
      src/embedded/man/files/main.n
  29. 313
      src/embedded/man/files/project_changes.n
  30. 297
      src/embedded/man/files/project_intro.n
  31. 8
      src/embedded/man/files/punk/_module_cap-0.1.0.tm.n
  32. 6
      src/embedded/man/files/punk/_module_path-0.1.0.tm.n
  33. 30
      src/embedded/man/files/punk/mix/commandset/_module_project-0.1.0.tm.n
  34. 57
      src/embedded/man/index.n
  35. 18
      src/embedded/man/toc.n
  36. 8
      src/embedded/md/.doc/tocdoc
  37. 2
      src/embedded/md/.idx
  38. 2
      src/embedded/md/.toc
  39. 2
      src/embedded/md/.xrf
  40. 8
      src/embedded/md/doc/files/main.md
  41. 75
      src/embedded/md/doc/files/project_changes.md
  42. 57
      src/embedded/md/doc/files/project_intro.md
  43. 21
      src/embedded/md/doc/files/punk/_module_cap-0.1.0.tm.md
  44. 13
      src/embedded/md/doc/files/punk/_module_path-0.1.0.tm.md
  45. 41
      src/embedded/md/doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md
  46. 12
      src/embedded/md/doc/toc.md
  47. 32
      src/embedded/md/index.md
  48. 12
      src/embedded/md/toc.md
  49. 8
      src/embedded/www/.doc/tocdoc
  50. 2
      src/embedded/www/.idx
  51. 2
      src/embedded/www/.toc
  52. 2
      src/embedded/www/.xrf
  53. 6
      src/embedded/www/doc/files/main.html
  54. 169
      src/embedded/www/doc/files/project_changes.html
  55. 145
      src/embedded/www/doc/files/project_intro.html
  56. 15
      src/embedded/www/doc/files/punk/_module_cap-0.1.0.tm.html
  57. 12
      src/embedded/www/doc/files/punk/_module_path-0.1.0.tm.html
  58. 26
      src/embedded/www/doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html
  59. 24
      src/embedded/www/doc/toc.html
  60. 47
      src/embedded/www/index.html
  61. 24
      src/embedded/www/toc.html
  62. 4
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/cap-0.1.0.tm
  63. 71
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/docgen-0.1.0.tm
  64. 153
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/du-0.1.0.tm
  65. 4
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/cli-0.3.tm
  66. 7
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm
  67. 2
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  68. 61
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm
  69. 73
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm
  70. 4
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/ns-0.1.0.tm
  71. 397
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/path-0.1.0.tm
  72. 40
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/repo-0.1.1.tm
  73. 2
      src/mixtemplates/layouts/basic/src/bootsupport/modules/punkcheck-0.1.0.tm
  74. 28
      src/modules/punk-0.1.tm
  75. 4
      src/modules/punk/cap-999999.0a1.0.tm
  76. 153
      src/modules/punk/du-999999.0a1.0.tm
  77. 4
      src/modules/punk/mix/cli-0.3.tm
  78. 7
      src/modules/punk/mix/commandset/doc-999999.0a1.0.tm
  79. 2
      src/modules/punk/mix/commandset/module-999999.0a1.0.tm
  80. 61
      src/modules/punk/mix/commandset/project-999999.0a1.0.tm
  81. 73
      src/modules/punk/mix/commandset/scriptwrap-999999.0a1.0.tm
  82. 6
      src/modules/punk/mix/templates/layouts/project/.fossil-settings/ignore-glob
  83. 4
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/cap-0.1.0.tm
  84. 71
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/docgen-0.1.0.tm
  85. 153
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/du-0.1.0.tm
  86. 4
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/cli-0.3.tm
  87. 7
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm
  88. 2
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  89. 61
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm
  90. 73
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm
  91. 4
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/ns-0.1.0.tm
  92. 397
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/path-0.1.0.tm
  93. 40
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/repo-0.1.1.tm
  94. 2
      src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punkcheck-0.1.0.tm
  95. 2
      src/modules/punk/mix/templates/layouts/project/src/doc/project_changes.man
  96. 2
      src/modules/punk/mix/templates/layouts/project/src/doc/project_intro.man
  97. 49
      src/modules/punk/mix/templates/modules/template_cli-0.0.1.tm
  98. 3
      src/modules/punk/mix/templates/modules/template_module-0.0.1.tm
  99. 270
      src/modules/punk/mix/templates/utility/scriptappwrappers/punk-multishell-old.cmd
  100. 57
      src/modules/punk/mix/templates/utility/scriptappwrappers/punk-multishell.cmd
  101. Some files were not shown because too many files have changed in this diff Show More

29
bin/dtplite.bat

@ -1,29 +0,0 @@
::lindex tcl;#\
@call tclsh "%~dp0%~n0.bat" %* & goto :eof
# --- --- --- --- --- --- --- --- --- --- --- --- ---begin Tcl
# -*- tcl -*-
# @@ Meta Begin
# Application dtplite 1.0.5
# Meta platform tcl
# Meta summary Lightweight DocTools Processor
# Meta description This application is a simple processor
# Meta description for documents written in the doctools
# Meta description markup language. It covers the most
# Meta description common use cases, but is not as
# Meta description configurable as its big brother dtp.
# Meta category Processing doctools documents
# Meta subject doctools doctoc docidx
# Meta require {dtplite 1.0.5}
# Meta author Andreas Kupries
# Meta license BSD
# @@ Meta End
package require dtplite 1.0.5
# dtp lite - Lightweight DocTools Processor
# ======== = ==============================
exit [dtplite::do $argv]
# ### ### ### ######### ######### #########
exit

28
bin/dtplite.tcl

@ -1,28 +0,0 @@
#! /usr/bin/env tclsh
# -*- tcl -*-
# @@ Meta Begin
# Application dtplite 1.0.5
# Meta platform tcl
# Meta summary Lightweight DocTools Processor
# Meta description This application is a simple processor
# Meta description for documents written in the doctools
# Meta description markup language. It covers the most
# Meta description common use cases, but is not as
# Meta description configurable as its big brother dtp.
# Meta category Processing doctools documents
# Meta subject doctools doctoc docidx
# Meta require {dtplite 1.0.5}
# Meta author Andreas Kupries
# Meta license BSD
# @@ Meta End
package require dtplite 1.0.5
# dtp lite - Lightweight DocTools Processor
# ======== = ==============================
exit [dtplite::do $argv]
# ### ### ### ######### ######### #########
exit

46
bin/kettle.bat

@ -1,46 +0,0 @@
::lindex tcl;#\
@call tclsh "%~dp0%~n0.bat" %* & goto :eof
# --- --- --- --- --- --- --- --- --- --- --- --- ---begin Tcl
#!/usr/bin/env C:/tcl/bin/tclsh.exe
# -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## Kettle application
# @@ Meta Begin
# Application kettle 1
# Meta author {Andreas Kupries}
# Meta build::by jnoble
# Meta build::date 2023-07-20
# Meta category Builder/Developer support
# Meta description Kettle is a system to make building Tcl packages quick
# Meta description and easy. More importantly, possibly, to make writing
# Meta description the build system for Tcl packages easy. As such kettle
# Meta description is several things: (1) A DSL helping you to write build
# Meta description systems for your packages. (2) A package implementing
# Meta description this DSL. (3) An application which can serve as the
# Meta description interpreter for a build file containing commands in the
# Meta description above DSL.
# Meta location https://core.tcl.tk/akupries/kettle
# Meta platform tcl
# Meta require {Tcl 8.5-}
# Meta require kettle
# Meta subject {build support} critcl teapot {meta data} doctools
# Meta subject diagram
# Meta summary Build support application.
# Meta vc::revision fatal: No annotated tags can describe
# Meta vc::revision '96a08d425f3f151966cea8a0005758fd97115958'.
# Meta vc::system git
# @@ Meta End
apply {{self} {
set selfdir [file dirname $self]
if {[file exists $selfdir/kettle.tcl]} {
# Look for a local copy first, for when we install ourselves.
source $selfdir/kettle.tcl
} else {
# use the installed core.
package require kettle
}
kettle::option::set @kettle $self
kettle::Application
}} [file dirname [file normalize [info script]/__]]

12
src/bootsupport/include_modules.config

@ -7,25 +7,27 @@ set bootsupport_modules [list\
src/vendormodules http\
modules punkcheck\
modules punk::ns\
modules punk::path\
modules punk::cap\
modules punk::cap::handlers::caphandler\
modules punk::cap::handlers::scriptlibs\
modules punk::cap::handlers::templates\
modules punk::du\
modules punk::docgen\
modules punk::mix\
modules punk::mix::base\
modules punk::mix::cli\
modules punk::mix::util\
modules punk::mix::templates\
modules punk::mix::commandset::module\
modules punk::mix::commandset::buildsuite\
modules punk::mix::commandset::debug\
modules punk::mix::commandset::repo\
modules punk::mix::commandset::doc\
modules punk::mix::commandset::layout\
modules punk::mix::commandset::loadedlib\
modules punk::mix::commandset::module\
modules punk::mix::commandset::project\
modules punk::mix::commandset::layout\
modules punk::mix::commandset::buildsuite\
modules punk::mix::commandset::repo\
modules punk::mix::commandset::scriptwrap\
modules punk::mix::commandset::doc\
modules punk::overlay\
modules punk::repo\
modules punk::tdl\

4
src/bootsupport/modules/punk/cap-0.1.0.tm

@ -15,14 +15,16 @@
#*** !doctools
#[manpage_begin punk::cap 0 0.1.0]
#[manpage_begin punkshell_module_punk::cap 0 0.1.0]
#[copyright "2023 JMNoble - BSD licensed"]
#[titledesc {capability provider and handler plugin system}]
#[moddesc {punk capabilities plugin system}]
#[require punk::cap]
#[description]
#[keywords module capability plugin]
#[section Overview]
#[para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.
#[para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters
#[subsection Concepts]
#[para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API
#

71
src/bootsupport/modules/punk/docgen-0.1.0.tm

@ -0,0 +1,71 @@
# -*- tcl -*
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::docgen 0.1.0
# Meta platform tcl
# Meta license BSD
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
##e.g package require frobz
package require punk::repo
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::docgen {
proc get_doctools_comments {fname} {
#does no validation of doctools commands
#existence of string match #\**!doctools is taken as evidence enough that the file has inline doctools - review
if {![file exists $fname]} {
error "get_doctools_comments file '$fname' not found"
}
set fd [open $fname r]
set data [read $fd]
close $fd
if {![string match "*#\**!doctools*" $data]} {
return
}
set data [string map [list \r\n \n] $data]
set in_doctools 0
set doctools ""
foreach ln [split $data \n] {
set ln [string trim $ln]
if {$in_doctools && [string index $ln 0] != "#"} {
set in_doctools 0
} elseif {[string range $ln 0 1] == "#*"} {
#todo - process doctools ordering hints in tail of line
set in_doctools 1
} elseif {$in_doctools} {
append doctools [string range $ln 1 end] \n
}
}
return $doctools
}
#todo - proc autogen_doctools_comments {fname} {}
# - will probably need to use something like parsetcl - as we won't be able to reliably source in an interp without side-effects and use info body etc.
# - mechanism will be to autodocument namespaces, procs, methods where no #*** doctools indication present - but use existing doctools comments for that particular item if it is present.
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::docgen [namespace eval punk::docgen {
variable pkg punk::docgen
variable version
set version 0.1.0
}]
return

153
src/bootsupport/modules/punk/du-0.1.0.tm

@ -837,7 +837,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -921,48 +921,10 @@ namespace eval punk::du {
set dirs [struct::set difference [concat $hdirs $dirs[unset dirs]] [concat $links [list [file join $folderpath .] [file join $folderpath ..] ]]]
set links [lsort -unique [concat $links $hlinks]]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
#----
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
if {"windows" eq $::tcl_platform(platform)} {
@ -979,7 +941,7 @@ namespace eval punk::du {
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
proc du_dirlisting_tclvfs {folderpath args} {
@ -995,7 +957,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1048,55 +1010,14 @@ namespace eval punk::du {
#nested vfs mount.. REVIEW - does anything need special handling?
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
#we can halve the number of round trips on unix-like systems, where 'hidden' always corresponds to dotted files
@ -1107,7 +1028,7 @@ namespace eval punk::du {
-with_times 0\
]
set errors [dict create]
dict lappend errors $folderpath "metdata support incomplete - prefer du_dirlisting_generic"
dict lappend errors $folderpath "metadata support incomplete - prefer du_dirlisting_generic"
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob]
@ -1115,7 +1036,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1165,14 +1086,64 @@ namespace eval punk::du {
set files [struct::set difference $files[unset files] $links]
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes {} times {} flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
}
#return fsizes,allsizes,alltimes metadata in same order as files,dirs,links lists - if specified in sized_types
proc du_get_metadata_lists {sized_types timed_types files dirs links} {
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
#subst with na if empty?
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
#todo - fix . The list lengths will presumably match but have empty values if failed to stat
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
return [dict create fsizes $fsizes allsizes $allsizes alltimes $alltimes]
}
proc du_lit value {

4
src/bootsupport/modules/punk/mix/cli-0.3.tm

@ -867,6 +867,7 @@ namespace eval punk::mix::cli {
::kettle option set @srcscript $path
::kettle option set @srcdir [file dirname $path]
::kettle option set @goals $goals
#load standard recipes as listed in build.tcl
::source $path
puts stderr "recipes: [::kettle recipe names]"
::kettle recipe run {*}[::kettle option get @goals]
@ -884,6 +885,9 @@ namespace eval punk::mix::cli {
}
}
proc kettle_punk_recipes {} {
set txtdst ...
}
}
}

7
src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm

@ -173,9 +173,12 @@ namespace eval punk::mix::commandset::doc {
return $result
}
set original_wd [pwd]
cd $projectdir/src
set docroot $projectdir/src/doc
cd $docroot
dtplite validate $docroot
punk::mix::cli::lib::kettle_call lib validate-doc
#punk::mix::cli::lib::kettle_call lib validate-doc
cd $original_wd
}

2
src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -273,7 +273,7 @@ namespace eval punk::mix::commandset::module {
set infile_version $build_version
}
set template_filedata [string map [list %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set template_filedata [string map [list %project% $projectname %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set modulefile $modulefolder/${moduletail}-$infile_version.tm
if {[file exists $modulefile]} {

61
src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm

@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punk::mix::commandset::project 0 0.1.0]
#[manpage_begin punkshell_module_punk::mix::commandset::project 0 0.1.0]
#[copyright "2023"]
#[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}]
#[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}]
@ -44,7 +44,7 @@
#[para] Where the . in the above example is the prefix/command separator
#[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.
#[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname>
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects.<procname>
#[para]
#[subsection Concepts]
#[para] see punk::overlay
@ -498,11 +498,25 @@ namespace eval punk::mix::commandset::project {
#[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}]
namespace eval collection {
#*** !doctools
#[subsection {Namespace punk::mix::commandset::project::collection}]
#[para] commandset functions for operating with multiple projects.
#[para] It would usually be imported with the prefix "projects" and separator "." to result in commands such as: <ensemblecommand> projects.detail
#[list_begin definitions]
namespace export *
namespace path [namespace parent]
#e.g imported as 'projects'
proc _default {{glob {}} args} {
#*** !doctools
#[call [fun _default] [arg glob] [opt {option value...}]]
#[para]List projects under fossil management, showing fossil db location and number of checkouts
#[para]The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
#[para]glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s
#[para]The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.
#[para]e.g
#[para] punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection
#[para]Will result in the command being available as <ensemblecommand> projects
package require overtype
set db_projects [lib::get_projects $glob]
set col1items [lsearch -all -inline -index 0 -subindices $db_projects *]
@ -510,7 +524,7 @@ namespace eval punk::mix::commandset::project {
set checkouts [lsearch -all -inline -index 2 -subindices $db_projects *]
set col3items [lmap v $checkouts {llength $v}]
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1items] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -596,7 +610,7 @@ namespace eval punk::mix::commandset::project {
}
}
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1_dbfiles] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -656,15 +670,27 @@ namespace eval punk::mix::commandset::project {
proc work {{glob {}} args} {
package require sqlite3
set db_projects [lib::get_projects $glob]
if {[llength $db_projects] == 0} {
puts stderr "::punk::mix::commandset::project::work No Repo DB name matches found for '$glob'"
return ""
}
#list of lists of the form:
#{fosdb fname workdirlist}
set defaults [dict create\
-cd 0\
-detail "\uFFFF"\
]
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- ---
set opt_cd [dict get $opts -cd]
# -- --- --- --- --- --- ---
set opt_detail [dict get $opts -detail]
set opt_detail_explicit_zero 1 ;#default assumption only
if {$opt_detail eq "\uFFFF"} {
set opt_detail_explicit_zero 0
set opt_detail 0; #default
}
# -- --- --- --- --- --- ---
set workdir_dict [dict create]
set all_workdirs [list]
foreach pinfo $db_projects {
@ -732,10 +758,17 @@ namespace eval punk::mix::commandset::project {
set col_states [list]
set state_title ""
#if only one set of fossil checkouts in the resultset - retrieve workingdir state for each co
if {[llength [dict keys $fosdb_cache]] == 1} {
puts stderr "Result is a single project - gathering file state for each checkout folder"
#if only one set of fossil checkouts in the resultset and opt_detail is 0 and not explicit - retrieve workingdir state for each co
if {([llength [dict keys $fosdb_cache]] == 1)} {
if {!$opt_detail_explicit_zero} {
set opt_detail 1
}
puts stderr "Result is from a single repo db [dict keys $fosdb_cache]"
}
if {$opt_detail} {
puts stderr "Gathering file state for [llength $workdirs] checkout folder(s). Use -detail 0 to omit file state"
set c_rev [list]
set c_rev_iso [list]
set c_unchanged [list]
set c_changed [list]
set c_new [list]
@ -745,6 +778,7 @@ namespace eval punk::mix::commandset::project {
set wd_state [punk::repo::workingdir_state $wd]
set state_dict [punk::repo::workingdir_state_summary_dict $wd_state]
lappend c_rev [string range [dict get $state_dict revision] 0 9]
lappend c_rev_iso [dict get $state_dict revision_iso8601]
lappend c_unchanged [dict get $state_dict unchanged]
lappend c_changed [dict get $state_dict changed]
lappend c_new [dict get $state_dict new]
@ -756,6 +790,9 @@ namespace eval punk::mix::commandset::project {
set t0 "Revision"
set w0 [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev] {string length $v}]]
set c0 [string repeat " " $w0]
set t0b "Revision iso8601"
set w0b [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev_iso] {string length $v}]]
set c0b [string repeat " " $w0b]
set t1 "Unch"
set w1 [tcl::mathfunc::max {*}[lmap v [concat [list $t1] $c_unchanged] {string length $v}]]
set c1 [string repeat " " $w1]
@ -772,9 +809,9 @@ namespace eval punk::mix::commandset::project {
set w5 [tcl::mathfunc::max {*}[lmap v [concat [list $t5] $c_extra] {string length $v}]]
set c5 [string repeat " " $w5]
set state_title "[overtype::left $c0 $t0] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
set state_title "[overtype::left $c0 $t0] [overtype::left $c0b $t0b] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev iso $c_rev_iso u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::left $c0b $iso] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
}
}
@ -789,7 +826,7 @@ namespace eval punk::mix::commandset::project {
set title1 "Checkout dir"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $workdirs] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "Db name"
set title2 "Repo DB name"
set widest2 [tcl::mathfunc::max {*}[lmap v [concat [list $title2] $col_fnames] {string length $v}]]
set col2 [string repeat " " $widest2]
set title3 "CO dup"
@ -851,6 +888,8 @@ namespace eval punk::mix::commandset::project {
}
return $msg
}
#*** !doctools
#[list_end] [comment {-- end collection namespace definitions --}]
}
namespace eval lib {

73
src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm

@ -100,13 +100,18 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the tcl-payload or xxx-payload-pre-tcl site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} {
set defaults [list -askme 1 -template \uFFFF]
set opts [dict merge $defaults $args]
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
set defaults [dict create\
-askme 1\
-outputfolder "\uFFFF"\
-template "\uFFFF"\
]
set known_opts [dict keys $defaults]
dict for {k v} $args {
if {$k ni $known_opts} {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts"
}
}
set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -116,6 +121,17 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
}
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set opt_outputfolder [dict get $opts -outputfolder]
# -- --- --- --- --- --- --- --- --- --- --- ---
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
#first check if relative or absolute path matches a file
@ -124,7 +140,6 @@ namespace eval punk::mix::commandset::scriptwrap {
} else {
set specified_path [file join $startdir $filepath_or_scriptset]
}
set ext [string trim [file extension $filepath_or_scriptset] .]
set allowed_extensions [list wrapconfig tcl ps1 sh bash]
#set allowed_extensions [list tcl]
@ -203,7 +218,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
} else {
if {[file pathtype $something_found] ne "file"} {
if {[file type $something_found] ne "file"} {
puts stderr "Found '$something_found'"
puts stderr "wrap_in_multishell doesn't currently support a directory as the path."
puts stderr $usage
return false
@ -280,11 +296,37 @@ namespace eval punk::mix::commandset::scriptwrap {
}
#todo
#output_file extension depends on the template being used..
if {$opt_outputfolder eq "\uFFFF"} {
#outputfolder not explicitly specified by caller
if {[string length $projectroot]} {
set output_folder [file join $projectroot/bin]
} else {
set output_folder $startdir
}
} else {
if {[file pathtype $opt_outputfolder] eq "relative"} {
if {[string length $projectroot]} {
set output_folder [file join $projectroot $opt_outputfolder]
} else {
set output_folder [file join $startdir $opt_outputfolder]
}
} else {
set output_folder $opt_outputfolder
}
}
if {![file isdirectory $output_folder]} {
error "wrap_in_multishell: output folder '$output_folder' not found. Please ensure target directory exists"
}
set output_file $scriptset.cmd
#todo
#output_file extension may also depend on the template being used.. and/or the .wrapconfig
if {$::tcl_platform(platform) eq "windows"} {
set output_extension cmd
} else {
set output_extension sh
}
set output_file [file join $output_folder $scriptset.$output_extension]
if {[file exists $output_file]} {
error "wrap_in_multishell: target file $output_file already exists.. aborting"
}
@ -308,7 +350,7 @@ namespace eval punk::mix::commandset::scriptwrap {
set list_input_files [list]
if {$process_extensions eq "ALLFOUNDORCONFIGURED"} {
#todo - look for .wrapconfig or all extensions for the scriptset
puts stderr "Sorry - only single input file supported - implementation incomplete"
puts stderr "Sorry - only single input file supported. Supply a file extension or use a .wrapconfig with a single input file for now - implementation incomplete"
return false
} else {
lappend list_input_files $scriptroot/$scriptset.$ext
@ -332,8 +374,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stdout $ln
}
puts stdout "-----------------------------------------------\n"
if {$opt_askme} {
puts stdout "Target for above data is '$output_file'"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
@ -394,6 +436,11 @@ namespace eval punk::mix::commandset::scriptwrap {
puts -nonewline $fdtarget $newscript
close $fdtarget
puts stdout "Wrote script file at $output_file"
#even though chmod might exist on windows - we will leave permissions alone
if {$::tcl_platform(platform) ne "windows"} {
catch {exec chmod +x $output_file}
}
puts stdout "-done-"
return $output_file
}

4
src/bootsupport/modules/punk/ns-0.1.0.tm

@ -1547,6 +1547,7 @@ namespace eval punk::ns {
foreach fullv $varnames {
set v [namespace tail $fullv]
upvar 1 $v var
if {[info exists var]} {
if {$v eq "args"} {
dict set capturevars "prev_args$n" [list var $var]
} else {
@ -1556,6 +1557,9 @@ namespace eval punk::ns {
dict set capturearrs $v [array get var]
}
}
} else {
#A variable can show in the results for 'info vars' (or nsvars) but still not exist. e.g a 'variable x' declaration in the namespace where the variable has never been set
}
}
return [dict create vars $capturevars arrs $capturearrs]
} } [info vars [namespace current]::*] ;#we are relying on info vars ::::* returning same as info vars ::* - a bit hacky (don't want to set any extra vars in the ns)

397
src/bootsupport/modules/punk/path-0.1.0.tm

@ -0,0 +1,397 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::path 0.1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.1.0]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
#[require punk::path]
#[description]
#[keywords module path filesystem]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::path
#[para] Filesystem path utility functions
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::path
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::class {
#*** !doctools
#[subsection {Namespace punk::path::class}]
#[para] class definitions
if {[info commands [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 ---}]
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path {
namespace export *
#variable xyz
#*** !doctools
#[subsection {Namespace punk::path}]
#[para] Core API functions for punk::path
#[list_begin definitions]
proc pathglob_as_re {pathglob} {
#*** !doctools
#[call [fun pathglob_as_re] [arg pathglob]]
#[para] Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure
#[para] ** matches any number of subdirectories.
#[para] e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself)
#[para] e.g /etc/**.txt will match any .txt files at any depth below /etc
#[para] any segment that does not contain ** must match exactly one segment in the path
#[para] e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc
#[para] The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified.
#[para] Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals
#todo - consider whether a way to escape the glob chars ? * is practical - to allow literals ? *
# - would require counting immediately-preceding backslashes
set pats [list]
foreach seg [file split $pathglob] {
if {[string range $seg end end] eq "/"} {
set seg [string range $seg 0 end-1] ;# e.g c:/ -> c: / -> "" so that join at end doesn't double up
}
if {$seg eq "*"} {
lappend pats {[^/]*}
} elseif {$seg eq "**"} {
lappend pats {.*}
} else {
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals
set seg [string map [list . {[.]}] $seg]
if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg]
lappend pats "$pat"
} else {
lappend pats "$seg"
}
}
}
return "^[join $pats /]\$"
}
proc globmatchpath {pathglob path args} {
#*** !doctools
#[call [fun globmatchpath] [arg pathglob] [arg path] [opt {option value...}]]
#[para] Return true if the pathglob matches the path
#[para] see [fun pathglob_as_re] for pathglob description
#[para] Caller must ensure that file separator is forward slash. (e.g use file normalize on windows)
#[para]
#[para] Known options:
#[para] -nocase 0|1 (default 0 - case sensitive)
#[para] If -nocase is not supplied - default to case sensitive *except for driveletter*
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.
set defaults [dict create\
-nocase \uFFFF\
]
set known_opts [dict keys $defaults]
set opts [dict merge $defaults $args]
dict for {k v} $args {
if {$k ni $known_opts} {
error "Unrecognised options $k - known options: $known_opts"
}
}
# -- --- --- --- --- ---
set opt_nocase [dict get $opts -nocase]
set explicit_nocase 1 ;#default to disprove
if {$opt_nocase eq "\uFFFF"} {
set opt_nocase 0
set explicit_nocase 0
}
# -- --- --- --- --- ---
if {$opt_nocase} {
return [regexp -nocase [pathglob_as_re $pathglob] $path]
} else {
set re [pathglob_as_re $pathglob]
if {$explicit_nocase} {
set ismatch [regexp $re $path] ;#explicit -nocase 0 - require exact match of path literals including driveletter
} else {
#caller is using default for -nocase - which indicates case sensitivity - but we have an exception for the driveletter.
set re_segments [file split $re] ;#Note that file split c:/etc gives {c:/ etc} but file split ^c:/etc gives {^c: etc}
set first_seg [lindex $re_segments 0]
if {[regexp {^\^(.{1}):$} $first_seg _match driveletter]} {
#first part of re is like "^c:" i.e a drive letter
set chars [string tolower $driveletter][string toupper $driveletter]
set re [join [concat "^\[$chars\]:" [lrange $re_segments 1 end]] /] ;#rebuild re with case insensitive driveletter only - use join - not file join. file join will misinterpret leading re segment.
}
#puts stderr "-->re: $re"
set ismatch [regexp $re $path]
}
}
return $ismatch
}
#todo - implement treefiles which acts like dirfiles but allows path globbing in the same way as punk::ns::ns/
#then review if treefiles can replace dirfiles or if both should exist (dirfiles can have literal glob chars in path segments - but that is a rare usecase)
proc treefilenames {basepath tailglob args} {
#*** !doctools
#[call [fun treefilenames] [arg basepath] [arg tailglob] [opt {option value...}]]
#basic (glob based) list of filenames matching tailglob - recursive
#no natsorting - so order is dependent on filesystem
set defaults [dict create\
-call-depth-internal 0\
-antiglob_paths {}\
]
set opts [dict merge $defaults $args]
set opt_antiglob_paths [dict get $opts -antiglob_paths]
set CALLDEPTH [dict get $opts -call-depth-internal]
set files [list]
if {$CALLDEPTH == 0} {
if {![file isdirectory $basepath]} {
return [list]
}
}
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $basepath]} {
set skip 1
break
}
}
if {$skip} {
return [list]
}
#todo - account for vfs where matched path could appear to be a directory but is mounted so could be a desired match?
set dirfiles [glob -nocomplain -dir $basepath -type f $tailglob]
lappend files {*}$dirfiles
set dirdirs [glob -nocomplain -dir $basepath -type d *]
foreach dir $dirdirs {
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $dir]} {
set skip 1
break
}
}
if {$skip} {
continue
}
set nextargs [dict merge $args [list -call-depth-internal [incr CALLDEPTH]]]
lappend files {*}[treefilenames $dir $tailglob {*}$nextargs]
}
return $files
}
#maint warning - also in punkcheck
proc relative {reference location} {
#*** !doctools
#[call [fun relative] [arg reference] [arg location]]
#[para] Taking two directory paths, a reference and a location, computes the path
# of the location relative to the reference.
#[list_begin itemized]
#[item]
#[para] Arguments:
# [list_begin arguments]
# [arg_def string reference] The path from which the relative path to location is determined.
# [arg_def string location] The location path which may be above or below the reference path
# [list_end]
#[item]
#[para] Results:
#[para] The relative path of the location to the reference path.
#[para] Will return a single dot "." if the paths are the same
#[item]
#[para] Notes:
#[para] Both paths must be the same type - ie both absolute or both relative
#[para] Case sensitive. ie relative /etc /etC
# will return ../etC
#[para] On windows, the drive-letter component (only) is not case sensitive
#[para] ie relative c:/etc C:/etc returns .
#[para] but relative c:/etc C:/Etc returns ../Etc
#[para] On windows, if the paths are absolute and specifiy different volumes, only the location will be returned.
# ie relative c:/etc d:/etc/blah
# returns d:/etc/blah
#[list_end]
#see also kettle
# Modified copy of ::fileutil::relative (tcllib)
# Adapted to 8.5 ({*}).
#review - check volume info on windows.. UNC paths?
if {[file pathtype $reference] ne [file pathtype $location]} {
return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $reference] vs. [file pathtype $location], ($reference vs. $location)"
}
#avoid normalizing if possible (file normalize *very* expensive on windows)
set do_normalize 0
if {[file pathtype $reference] eq "relative"} {
#if reference is relative so is location
if {[regexp {[.]{2}} [list $reference $location]]} {
set do_normalize 1
}
if {[regexp {[.]/} [list $reference $location]]} {
set do_normalize 1
}
} else {
set do_normalize 1
}
if {$do_normalize} {
set reference [file normalize $reference]
set location [file normalize $location]
}
set save $location
set reference [file split $reference]
set location [file split $location]
while {[lindex $location 0] eq [lindex $reference 0]} {
set location [lrange $location 1 end]
set reference [lrange $reference 1 end]
if {![llength $location]} {break}
}
set location_len [llength $location]
set reference_len [llength $reference]
if {($location_len == 0) && ($reference_len == 0)} {
# Cases:
# (a) reference == location
set location .
} else {
# Cases:
# (b) ref is: ref/sub = sub
# loc is: ref = {}
# (c) ref is: ref = {}
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
incr reference_len -1
}
set location [file join {*}$location]
}
return $location
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::lib {
namespace export *
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::path::lib}]
#[para] Secondary functions that are part of the API
#[list_begin definitions]
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::path::system {
#*** !doctools
#[subsection {Namespace punk::path::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.1.0
}]
return
#*** !doctools
#[manpage_end]

40
src/bootsupport/modules/punk/repo-0.1.1.tm

@ -314,6 +314,10 @@ namespace eval punk::repo {
# -repotypes is an ordered list - if the closest repo is multi-typed the order will determine which is used.
# This deliberately doesn't allow bypassing a sub-repo to look for a higher-level repo in a repo-nest.
# The theory is that sub-repos shouldn't have their contents directly tracked directly by higher-level repos anyway
#REVIEW - if closest repo is both fossil and git - we only return info for one, with fossil being preferenced
#This may not make sense if we want to allow fossil tracking of projects where git is the primary repotype and fossil is just used to enable us to enumerate projects?
#does a dual git/fossil repo make sense if both are committing??
# see: https://fossil-scm.org/home/doc/trunk/www/inout.wiki for bidirectional sync info
proc workingdir_state {{abspath {}} args} {
set defaults [list\
-repotypes [list fossil git]\
@ -364,6 +368,9 @@ namespace eval punk::repo {
}
set resultdict [dict create repodir $repodir subpath $subpath]
#set defaults in case no supported repotype found
set revision ""
set revision_iso8601 ""
set pathdict [dict create]
if {![llength $repotypes_to_query]} {
@ -384,9 +391,15 @@ namespace eval punk::repo {
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$fossil_cmd status --all --differ --merge $abspath]} fossilstate]} {
error "workingdir_state error: Unable to retrieve workingdir state using fossil. Errormsg: $fossilstate"
}
# line: checkout: fb971...
set revision [lindex [grep {checkout:*} $fossilstate] 0 1]
# line: checkout: fb971... Y-m-d H:M:S TZ
set checkout_info [lindex [grep {checkout:*} $fossilstate] 0] ;#grep returns a list - but it should always be a single match in this case
set revision [lindex $checkout_info 0 1]
#set checkrevision [fossil_revision $abspath]
lassign $checkout_info _key revision revision_ymd revision_hms revision_tz
if {$revision_tz eq "UTC"} {
set revision_tz "+0000" ;#normalize UTC for consistency with git tz output - review - should do date-math if necessary on git and fossil to bring all to +0000 (is fossil always UTC? git )
}
set revision_iso8601 "${revision_ymd}T${revision_hms}${revision_tz}"
dict set resultdict ahead ""
@ -442,6 +455,25 @@ namespace eval punk::repo {
puts stderr "workingdir_state: git revision is (initial) - no file state to gather"
break
}
# -- --- --- --- ---
#could use %ci for ISO8601 data - see git-show manpage, but this will be in timezone of developer's machine - we need it in UTC for comparison to fossil outputs and other devs
set had_TZ 0
if {[info exists ::env(TZ)]} {
set TZ_prev $::env(TZ)
set had_TZ 1
}
set ::env(TZ) "UTC0"
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$git_cmd show -s --date=format-local:%Y:%m:%dT%H:%M:%S+0000 --format=format:%cd -- $abspath]} revision_iso8601]} {
puts stderr "workingdir_state warning: Unable to retrieve workingdir state using git. Errormsg: $gitstate"
}
if {$had_TZ} {
set ::env(TZ) $TZ_prev
} else {
unset ::env(TZ)
}
# -- --- --- --- ---
dict set resultdict ahead ""
dict set resultdict behind ""
set aheadbehind [lindex [grep {# branch.ab *} $gitstate] 0]
@ -525,6 +557,7 @@ namespace eval punk::repo {
}
}
dict set resultdict revision $revision
dict set resultdict revision_iso8601 $revision_iso8601
dict set resultdict paths $pathdict
return $resultdict
}
@ -547,6 +580,7 @@ namespace eval punk::repo {
repodir repodir\
subpath subpath\
revision revision\
revision_iso8601 revision_iso8601\
ahead ahead\
behind behind\
repotype repotype\
@ -590,7 +624,7 @@ namespace eval punk::repo {
}
set filestates [dict values [dict get $repostate paths]]
set path_count_fields [list unchanged changed new missing extra]
set state_fields [list ahead behind repodir subpath repotype revision]
set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601]
set dresult [dict create]
foreach f $state_fields {
dict set dresult $f [dict get $repostate $f]

2
src/bootsupport/modules/punkcheck-0.1.0.tm

@ -743,7 +743,7 @@ namespace eval punkcheck {
#The files we depended on for the previous record haven't changed themselves - but the list of files has (reduced by one)
proc installfile_add_source_and_fetch_metadata {punkcheck_folder source_relpath file_record} {
if {![lib::is_file_record_inprogress $file_record]} {
error "installfile_add_source_and_fetch_metdata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
error "installfile_add_source_and_fetch_metadata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
}
set ts_start [clock microseconds]
set last_installrecord [lib::file_record_get_last_installrecord $file_record]

3
src/doc/include/changes.inc

@ -0,0 +1,3 @@
[section Changes]
[include changes_0.1.inc]

28
src/doc/include/changes_0.1.inc

@ -0,0 +1,28 @@
[subsection {Changes for version 0.1}]
This release 0.1 of project punkshell
[para] Summary
[list_begin enumerated]
[enum] feature 1
[enum] feature 2
[list_end]
[para] In detail:
[list_begin enumerated]
[comment {- - -- --- ----- -------- ------------- ---------------------}]
[enum] punkshell requires Tcl 8.6 or higher. Tcl 8.5 or less is not
supported.
[comment {- - -- --- ----- -------- ------------- ---------------------}]
[enum]
[comment {- - -- --- ----- -------- ------------- ---------------------}]
[list_end]
[comment {- - -- --- ----- -------- ------------- ---------------------}]

18
src/doc/include/feedback.inc

@ -0,0 +1,18 @@
[comment {-*- tcl -*- --- !doctools --- manpage}]
[comment {- - -- --- ----- -------- ------------- ---------------------}]
[section {Bugs, Ideas, Feedback}]
[vset project_tracker https://gitea1.intx.com.au/jn/punkshell/issues]
[vset project_email julian+punkshell@precisium.com.au]
This document, and the package it describes, will undoubtedly contain
bugs and other problems.
Please report such at the
[uri [vset project_tracker] {punkshell tracker}].
Please also report any ideas for enhancements you may have for either
package and/or documentation.
Contact: [uri mailto:[vset project_email] [vset project_email]]

2
src/doc/include/general.inc

@ -1,6 +1,6 @@
[comment {-*- tcl -*- --- !doctools --- manpage}]
[comment {- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---}]
[moddesc {punkshell - a Tcl }]
[moddesc {punkshell - a Tcl project}]
[category {shell}]
[keywords shell repl punk]
[require Tcl 8.6]

3
src/doc/include/punkshell.inc

@ -0,0 +1,3 @@
[comment {Please consider retaining a link to PunkShell to support the project}]
[vset punkshell_project https://www.gitea1.intx.com.au/jn/punkshell]
[para] This project uses [uri [vset punkshell_project] {PunkShell}] as a deployment management and documentation tool.

2
src/doc/include/welcome.inc

@ -2,5 +2,5 @@
[comment {- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---}]
[include welcome_basic.inc]
[para] Please read the document [term {punkshell - Introduction to punkshell}],
[para] Please read the document [term {Introduction to punkshell}],
if you have not done so already, to get an overview of the whole system.

15
src/doc/project_changes.man

@ -0,0 +1,15 @@
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin punkshell__project_changes n 8]
[include include/general.inc]
[category changelog] [comment {-- override category from general.inc -- }]
[keywords changelog] [comment {-- additional keyword to those from general.inc --}]
[titledesc {punkshell Changes}]
[description]
[include include/welcome_basic.inc]
[para]
This document provides an overview of the changes [package punkshell]
underwent from version to version.
[include include/changes.inc]
[include include/feedback.inc]
[manpage_end]

15
src/doc/project_intro.man

@ -0,0 +1,15 @@
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin punkshell__project_intro n 8]
[include include/general.inc]
[titledesc {Introduction to punkshell}]
[description]
[include include/welcome_basic.inc]
[para]
Introduction to punkshell
[include include/feedback.inc]
[comment {Please consider retaining a link to PunkShell to support the project}]
[include include/punkshell.inc]
[manpage_end]

4
src/doc/punk/_module_cap-0.1.0.tm.man

@ -1,14 +1,16 @@
[comment {--- punk::docgen generated from inline doctools comments ---}]
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}]
[comment {--- punk::docgen overwrites this file ---}]
[manpage_begin punk::cap 0 0.1.0]
[manpage_begin punkshell_module_punk::cap 0 0.1.0]
[copyright "2023 JMNoble - BSD licensed"]
[titledesc {capability provider and handler plugin system}]
[moddesc {punk capabilities plugin system}]
[require punk::cap]
[description]
[keywords module capability plugin]
[section Overview]
[para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.
[para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters
[subsection Concepts]
[para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API

3
src/doc/punk/_module_path-0.1.0.tm.man

@ -1,12 +1,13 @@
[comment {--- punk::docgen generated from inline doctools comments ---}]
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}]
[comment {--- punk::docgen overwrites this file ---}]
[manpage_begin punk::path 0 0.1.0]
[manpage_begin punkshell_module_punk::path 0 0.1.0]
[copyright "2023"]
[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
[require punk::path]
[description]
[keywords module path filesystem]
[section Overview]
[para] overview of punk::path
[para] Filesystem path utility functions

17
src/doc/punk/mix/commandset/_module_project-0.1.0.tm.man

@ -1,7 +1,7 @@
[comment {--- punk::docgen generated from inline doctools comments ---}]
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}]
[comment {--- punk::docgen overwrites this file ---}]
[manpage_begin punk::mix::commandset::project 0 0.1.0]
[manpage_begin punkshell_module_punk::mix::commandset::project 0 0.1.0]
[copyright "2023"]
[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}]
[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}]
@ -24,7 +24,7 @@
[para] Where the . in the above example is the prefix/command separator
[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.
[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new
[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname>
[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects.<procname>
[para]
[subsection Concepts]
[para] see punk::overlay
@ -45,4 +45,17 @@
new project structure - may be dedicated to one module, or contain many.
create minimal folder structure only by specifying in args: -modules {}
[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}]
[subsection {Namespace punk::mix::commandset::project::collection}]
[para] commandset functions for operating with multiple projects.
[para] It would usually be imported with the prefix "projects" and separator "." to result in commands such as: <ensemblecommand> projects.detail
[list_begin definitions]
[call [fun _default] [arg glob] [opt {option value...}]]
[para]List projects under fossil management, showing fossil db location and number of checkouts
[para]The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
[para]glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s
[para]The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.
[para]e.g
[para] punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection
[para]Will result in the command being available as <ensemblecommand> projects
[list_end] [comment {-- end collection namespace definitions --}]
[manpage_end]

4
src/embedded/man/files/main.n

@ -1,7 +1,7 @@
'\"
'\" Generated from file 'main\&.man' by tcllib/doctools with format 'nroff'
'\"
.TH "punkshell" n 1 doc "punkshell - a Tcl"
.TH "punkshell" n 1 doc "punkshell - a Tcl project"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
@ -281,7 +281,7 @@ package require \fBTcl 8\&.6\fR
.PP
Welcome to the punkshell project\&.
.PP
Please read the document \fIpunkshell - Introduction to punkshell\fR,
Please read the document \fIIntroduction to punkshell\fR,
if you have not done so already, to get an overview of the whole system\&.
.PP
This document is the reference to commands and modules provided by punkshell

313
src/embedded/man/files/project_changes.n

@ -0,0 +1,313 @@
'\"
'\" Generated from file 'project_changes\&.man' by tcllib/doctools with format 'nroff'
'\"
.TH "punkshell__project_changes" n 8 doc "punkshell - a Tcl project"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
punkshell__project_changes \- punkshell Changes
.SH SYNOPSIS
package require \fBTcl 8\&.6\fR
.sp
.BE
.SH DESCRIPTION
.PP
Welcome to the punkshell project\&.
.PP
This document provides an overview of the changes \fBpunkshell\fR
underwent from version to version\&.
.SH CHANGES
.SS "CHANGES FOR VERSION 0\&.1"
This release 0\&.1 of project punkshell
.PP
Summary
.IP [1]
feature 1
.IP [2]
feature 2
.PP
.PP
In detail:
.IP [1]
punkshell requires Tcl 8\&.6 or higher\&. Tcl 8\&.5 or less is not
supported\&.
.IP [2]
.PP
.SH "BUGS, IDEAS, FEEDBACK"
This document, and the package it describes, will undoubtedly contain
bugs and other problems\&.
Please report such at the
\fIpunkshell tracker\fR [https://gitea1\&.intx\&.com\&.au/jn/punkshell/issues]\&.
Please also report any ideas for enhancements you may have for either
package and/or documentation\&.
Contact: \fIjulian+punkshell@precisium\&.com\&.au\fR [mailto:julian+punkshell@precisium\&.com\&.au]
.SH KEYWORDS
changelog, punk, repl, shell
.SH CATEGORY
changelog

297
src/embedded/man/files/project_intro.n

@ -0,0 +1,297 @@
'\"
'\" Generated from file 'project_intro\&.man' by tcllib/doctools with format 'nroff'
'\"
.TH "punkshell__project_intro" n 8 doc "punkshell - a Tcl project"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
punkshell__project_intro \- Introduction to punkshell
.SH SYNOPSIS
package require \fBTcl 8\&.6\fR
.sp
.BE
.SH DESCRIPTION
.PP
Welcome to the punkshell project\&.
.PP
Introduction to punkshell
.SH "BUGS, IDEAS, FEEDBACK"
This document, and the package it describes, will undoubtedly contain
bugs and other problems\&.
Please report such at the
\fIpunkshell tracker\fR [https://gitea1\&.intx\&.com\&.au/jn/punkshell/issues]\&.
Please also report any ideas for enhancements you may have for either
package and/or documentation\&.
Contact: \fIjulian+punkshell@precisium\&.com\&.au\fR [mailto:julian+punkshell@precisium\&.com\&.au]
.PP
This project uses \fIPunkShell\fR [https://www\&.gitea1\&.intx\&.com\&.au/jn/punkshell] as a deployment management and documentation tool\&.
.SH KEYWORDS
punk, repl, shell
.SH CATEGORY
shell

8
src/embedded/man/files/punk/_module_cap-0.1.0.tm.n

@ -2,7 +2,7 @@
'\" Generated from file '_module_cap-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2023 JMNoble - BSD licensed
'\"
.TH "punk::cap" 0 0\&.1\&.0 doc "punk capabilities plugin system"
.TH "punkshell_module_punk::cap" 0 0\&.1\&.0 doc "punk capabilities plugin system"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
@ -272,7 +272,7 @@ Database Class: \\fB\\$3\\fR
..
.BS
.SH NAME
punk::cap \- capability provider and handler plugin system
punkshell_module_punk::cap \- capability provider and handler plugin system
.SH SYNOPSIS
package require \fBpunk::cap \fR
.sp
@ -303,6 +303,8 @@ advanced::\fBdemote_provider\fR \fIpkg\fR
.SH OVERVIEW
.PP
punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability\&.
.PP
see also \fItcllib pluginmgr\fR [https://core\&.tcl-lang\&.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr\&.md] for an alternative which uses safe interpreters
.SS CONCEPTS
.PP
A \fIcapability\fR may be something like providing a folder of files, or just a data dictionary, and/or an API
@ -491,6 +493,8 @@ The active handler may or may not utilise this for preferencing\&. See documenta
.PP
Internal functions used to communicate between punk::cap and capability handlers
.PP
.SH KEYWORDS
capability, module, plugin
.SH COPYRIGHT
.nf
Copyright (c) 2023 JMNoble - BSD licensed

6
src/embedded/man/files/punk/_module_path-0.1.0.tm.n

@ -2,7 +2,7 @@
'\" Generated from file '_module_path-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2023
'\"
.TH "punk::path" 0 0\&.1\&.0 doc "punk path filesystem utils"
.TH "punkshell_module_punk::path" 0 0\&.1\&.0 doc "punk path filesystem utils"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
@ -272,7 +272,7 @@ Database Class: \\fB\\$3\\fR
..
.BS
.SH NAME
punk::path \- Filesystem path utilities
punkshell_module_punk::path \- Filesystem path utilities
.SH SYNOPSIS
package require \fBpunk::path \fR
.sp
@ -401,6 +401,8 @@ Secondary functions that are part of the API
.SS "NAMESPACE PUNK::PATH::SYSTEM"
.PP
Internal functions that are not part of the API
.SH KEYWORDS
filesystem, module, path
.SH COPYRIGHT
.nf
Copyright (c) 2023

30
src/embedded/man/files/punk/mix/commandset/_module_project-0.1.0.tm.n

@ -2,7 +2,7 @@
'\" Generated from file '_module_project-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2023
'\"
.TH "punk::mix::commandset::project" 0 0\&.1\&.0 doc "pmix CLI commandset - project"
.TH "punkshell_module_punk::mix::commandset::project" 0 0\&.1\&.0 doc "pmix CLI commandset - project"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
@ -272,12 +272,14 @@ Database Class: \\fB\\$3\\fR
..
.BS
.SH NAME
punk::mix::commandset::project \- pmix commandset - project
punkshell_module_punk::mix::commandset::project \- pmix commandset - project
.SH SYNOPSIS
package require \fBpunk::mix::commandset::project \fR
.sp
\fBnew\fR \fInewprojectpath_or_name\fR ?args?
.sp
\fB_default\fR \fIglob\fR ?option value\&.\&.\&.?
.sp
.BE
.SH DESCRIPTION
.SH OVERVIEW
@ -306,7 +308,7 @@ The prefix ('project' in the above example) can be any string desired to disambi
.PP
The above results in the availability of the ensemble command: ::myproject::cli project\&.new, which is implemented in ::punk::mix::commandset::project::new
.PP
Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects\&.<procname>
Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects\&.<procname>
.PP
.SS CONCEPTS
.PP
@ -334,6 +336,28 @@ core commandset functions for punk::mix::commandset::project
new project structure - may be dedicated to one module, or contain many\&.
create minimal folder structure only by specifying in args: -modules {}
.PP
.SS "NAMESPACE PUNK::MIX::COMMANDSET::PROJECT::COLLECTION"
.PP
commandset functions for operating with multiple projects\&.
.PP
It would usually be imported with the prefix "projects" and separator "\&." to result in commands such as: <ensemblecommand> projects\&.detail
.TP
\fB_default\fR \fIglob\fR ?option value\&.\&.\&.?
.sp
List projects under fossil management, showing fossil db location and number of checkouts
.sp
The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
.sp
glob restricts output based on the name of the fossil db file e\&.g s* for all projects beginning with s
.sp
The _default function is made available in the ensemble by the name of the prefix used when importing the commandset\&.
.sp
e\&.g
.sp
punk::overlay::import_commandset projects \&. ::punk::mix::commandset::project::collection
.sp
Will result in the command being available as <ensemblecommand> projects
.PP
.SH COPYRIGHT
.nf
Copyright (c) 2023

57
src/embedded/man/index.n

@ -272,22 +272,79 @@ Database Class: \\fB\\$3\\fR
.SH INDEX
doc
.RS
capability
.RS
.TP
\fBfiles/punk/_module_cap-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::cap
.RE
changelog
.RS
.TP
\fBfiles/project_changes\&.n\fR
punkshell__project_changes
.RE
filesystem
.RS
.TP
\fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::path
.RE
module
.RS
.TP
\fBfiles/punk/_module_cap-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::cap
.TP
\fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::path
.RE
path
.RS
.TP
\fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::path
.RE
plugin
.RS
.TP
\fBfiles/punk/_module_cap-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::cap
.RE
punk
.RS
.TP
\fBfiles/main\&.n\fR
punkshell
.TP
\fBfiles/project_changes\&.n\fR
punkshell__project_changes
.TP
\fBfiles/project_intro\&.n\fR
punkshell__project_intro
.RE
repl
.RS
.TP
\fBfiles/main\&.n\fR
punkshell
.TP
\fBfiles/project_changes\&.n\fR
punkshell__project_changes
.TP
\fBfiles/project_intro\&.n\fR
punkshell__project_intro
.RE
shell
.RS
.TP
\fBfiles/main\&.n\fR
punkshell
.TP
\fBfiles/project_changes\&.n\fR
punkshell__project_changes
.TP
\fBfiles/project_intro\&.n\fR
punkshell__project_intro
.RE
.RE

18
src/embedded/man/toc.n

@ -273,14 +273,20 @@ Database Class: \\fB\\$3\\fR
doc
.RS
.TP
\fBpunk::cap\fR
\fBpunkshell\fR
\fIfiles/main\&.n\fR: punkshell - Core
.TP
\fBpunkshell__project_changes\fR
\fIfiles/project_changes\&.n\fR: punkshell Changes
.TP
\fBpunkshell__project_intro\fR
\fIfiles/project_intro\&.n\fR: Introduction to punkshell
.TP
\fBpunkshell_module_punk::cap\fR
\fIfiles/punk/_module_cap-0\&.1\&.0\&.tm\&.n\fR: capability provider and handler plugin system
.TP
\fBpunk::mix::commandset::project\fR
\fBpunkshell_module_punk::mix::commandset::project\fR
\fIfiles/punk/mix/commandset/_module_project-0\&.1\&.0\&.tm\&.n\fR: pmix commandset - project
.TP
\fBpunk::path\fR
\fBpunkshell_module_punk::path\fR
\fIfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR: Filesystem path utilities
.TP
\fBpunkshell\fR
\fIfiles/main\&.n\fR: punkshell - Core

8
src/embedded/md/.doc/tocdoc

@ -1,6 +1,8 @@
[toc_begin {Table Of Contents} doc]
[item doc/files/punk/_module_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project {pmix commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.md punk::path {Filesystem path utilities}]
[item doc/files/main.md punkshell {punkshell - Core}]
[item doc/files/project_changes.md punkshell__project_changes {punkshell Changes}]
[item doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}]
[item doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap {capability provider and handler plugin system}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {pmix commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}]
[toc_end]

2
src/embedded/md/.idx

@ -1 +1 @@
{shell {{doc/files/main.md punkshell}} punk {{doc/files/main.md punkshell}} repl {{doc/files/main.md punkshell}}} {{repl doc/files/main.md punkshell} . {shell doc/files/main.md punkshell} . {punk doc/files/main.md punkshell} .} 3 {shell shell punk punk repl repl}
{shell {{doc/files/project_intro.md punkshell__project_intro} {doc/files/project_changes.md punkshell__project_changes} {doc/files/main.md punkshell}} changelog {{doc/files/project_changes.md punkshell__project_changes}} filesystem {{doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path}} path {{doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path}} capability {{doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap}} module {{doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap} {doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path}} punk {{doc/files/project_intro.md punkshell__project_intro} {doc/files/project_changes.md punkshell__project_changes} {doc/files/main.md punkshell}} plugin {{doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap}} repl {{doc/files/project_intro.md punkshell__project_intro} {doc/files/project_changes.md punkshell__project_changes} {doc/files/main.md punkshell}}} {{changelog doc/files/project_changes.md punkshell__project_changes} . {shell doc/files/project_changes.md punkshell__project_changes} . {shell doc/files/main.md punkshell} . {repl doc/files/project_intro.md punkshell__project_intro} . {module doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap} . {plugin doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap} . {filesystem doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path} . {path doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path} . {module doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path} . {shell doc/files/project_intro.md punkshell__project_intro} . {punk doc/files/project_changes.md punkshell__project_changes} . {punk doc/files/main.md punkshell} . {repl doc/files/project_changes.md punkshell__project_changes} . {punk doc/files/project_intro.md punkshell__project_intro} . {repl doc/files/main.md punkshell} . {capability doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap} .} 9 {shell shell changelog changelog filesystem filesystem path path capability capability module module punk punk plugin plugin repl repl}

2
src/embedded/md/.toc

@ -1 +1 @@
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.md punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_path-0.1.0.tm.md punk::path {Filesystem path utilities}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.md punkshell {punkshell - Core}}}}
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}} {doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}} {doc/files/project_changes.md punkshell__project_changes {punkshell Changes}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.md punkshell {punkshell - Core}}}}

2
src/embedded/md/.xrf

@ -1 +1 @@
sa,punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.md punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md repl {index.md repl} kw,punk {index.md punk} punkshell(n) doc/files/main.md sa,punk::cap doc/files/punk/_module_cap-0.1.0.tm.md {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.md punkshell doc/files/main.md sa,punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md sa,punk::path doc/files/punk/_module_path-0.1.0.tm.md punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md shell {index.md shell} kw,repl {index.md repl} sa,punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md sa,punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md {punkshell - Core} doc/files/main.md {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md sa,punkshell(n) doc/files/main.md punk::cap doc/files/punk/_module_cap-0.1.0.tm.md sa,punkshell doc/files/main.md kw,shell {index.md shell} punk {index.md punk} punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md punk::path doc/files/punk/_module_path-0.1.0.tm.md
kw,capability {index.md capability} punkshell_module_punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md sa,punkshell_module_punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md {punkshell Changes} doc/files/project_changes.md {Introduction to punkshell} doc/files/project_intro.md punkshell_module_punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md sa,punkshell(n) doc/files/main.md filesystem {index.md filesystem} sa,punkshell doc/files/main.md kw,shell {index.md shell} sa,punkshell_module_punk::cap doc/files/punk/_module_cap-0.1.0.tm.md sa,punkshell_module_punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md sa,punkshell__project_changes(n) doc/files/project_changes.md kw,path {index.md path} kw,module {index.md module} punkshell(n) doc/files/main.md kw,plugin {index.md plugin} punkshell doc/files/main.md punkshell_module_punk::cap doc/files/punk/_module_cap-0.1.0.tm.md changelog {index.md changelog} punkshell_module_punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.md punkshell__project_changes(n) doc/files/project_changes.md sa,punkshell__project_changes doc/files/project_changes.md path {index.md path} sa,punkshell_module_punk::path doc/files/punk/_module_path-0.1.0.tm.md punkshell__project_changes doc/files/project_changes.md kw,filesystem {index.md filesystem} sa,punkshell_module_punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md shell {index.md shell} punkshell_module_punk::path doc/files/punk/_module_path-0.1.0.tm.md kw,repl {index.md repl} capability {index.md capability} punkshell_module_punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md {punkshell - Core} doc/files/main.md {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.md repl {index.md repl} kw,punk {index.md punk} sa,punkshell__project_intro(n) doc/files/project_intro.md sa,punkshell__project_intro doc/files/project_intro.md {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.md sa,punkshell_module_punk::path(0) doc/files/punk/_module_path-0.1.0.tm.md punkshell__project_intro(n) doc/files/project_intro.md punkshell__project_intro doc/files/project_intro.md kw,changelog {index.md changelog} punk {index.md punk} module {index.md module} plugin {index.md plugin}

8
src/embedded/md/doc/files/main.md

@ -1,7 +1,7 @@
[//000000001]: # (punkshell \- punkshell \- a Tcl )
[//000000001]: # (punkshell \- punkshell \- a Tcl project)
[//000000002]: # (Generated from file 'main\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (punkshell\(n\) 1 doc "punkshell \- a Tcl ")
[//000000003]: # (punkshell\(n\) 1 doc "punkshell \- a Tcl project")
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> &#124; <a
href="../toc.md">Table Of Contents</a> &#124; <a
@ -31,8 +31,8 @@ package require Tcl 8\.6
Welcome to the punkshell project\.
Please read the document *punkshell \- Introduction to punkshell*, if you have
not done so already, to get an overview of the whole system\.
Please read the document *[Introduction to punkshell](project\_intro\.md)*,
if you have not done so already, to get an overview of the whole system\.
This document is the reference to commands and modules provided by punkshell

75
src/embedded/md/doc/files/project_changes.md

@ -0,0 +1,75 @@
[//000000001]: # (punkshell\_\_project\_changes \- punkshell \- a Tcl project)
[//000000002]: # (Generated from file 'project\_changes\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (punkshell\_\_project\_changes\(n\) 8 doc "punkshell \- a Tcl project")
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> &#124; <a
href="../toc.md">Table Of Contents</a> &#124; <a
href="../../index.md">Keyword Index</a> ] <hr>
# NAME
punkshell\_\_project\_changes \- punkshell Changes
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Changes](#section2)
- [Changes for version 0\.1](#subsection1)
- [Bugs, Ideas, Feedback](#section3)
- [Keywords](#keywords)
- [Category](#category)
# <a name='synopsis'></a>SYNOPSIS
package require Tcl 8\.6
# <a name='description'></a>DESCRIPTION
Welcome to the punkshell project\.
This document provides an overview of the changes
__[punkshell](main\.md)__ underwent from version to version\.
# <a name='section2'></a>Changes
## <a name='subsection1'></a>Changes for version 0\.1
This release 0\.1 of project punkshell
Summary
1. feature 1
1. feature 2
In detail:
1. punkshell requires Tcl 8\.6 or higher\. Tcl 8\.5 or less is not supported\.
# <a name='section3'></a>Bugs, Ideas, Feedback
This document, and the package it describes, will undoubtedly contain bugs and
other problems\. Please report such at the [punkshell
tracker](https://gitea1\.intx\.com\.au/jn/punkshell/issues)\. Please also report
any ideas for enhancements you may have for either package and/or documentation\.
Contact:
[julian\+punkshell@precisium\.com\.au](mailto:julian\+punkshell@precisium\.com\.au)
# <a name='keywords'></a>KEYWORDS
[changelog](\.\./\.\./index\.md\#changelog), [punk](\.\./\.\./index\.md\#punk),
[repl](\.\./\.\./index\.md\#repl), [shell](\.\./\.\./index\.md\#shell)
# <a name='category'></a>CATEGORY
changelog

57
src/embedded/md/doc/files/project_intro.md

@ -0,0 +1,57 @@
[//000000001]: # (punkshell\_\_project\_intro \- punkshell \- a Tcl project)
[//000000002]: # (Generated from file 'project\_intro\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (punkshell\_\_project\_intro\(n\) 8 doc "punkshell \- a Tcl project")
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> &#124; <a
href="../toc.md">Table Of Contents</a> &#124; <a
href="../../index.md">Keyword Index</a> ] <hr>
# NAME
punkshell\_\_project\_intro \- Introduction to punkshell
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Bugs, Ideas, Feedback](#section2)
- [Keywords](#keywords)
- [Category](#category)
# <a name='synopsis'></a>SYNOPSIS
package require Tcl 8\.6
# <a name='description'></a>DESCRIPTION
Welcome to the punkshell project\.
Introduction to punkshell
# <a name='section2'></a>Bugs, Ideas, Feedback
This document, and the package it describes, will undoubtedly contain bugs and
other problems\. Please report such at the [punkshell
tracker](https://gitea1\.intx\.com\.au/jn/punkshell/issues)\. Please also report
any ideas for enhancements you may have for either package and/or documentation\.
Contact:
[julian\+punkshell@precisium\.com\.au](mailto:julian\+punkshell@precisium\.com\.au)
This project uses [PunkShell](https://www\.gitea1\.intx\.com\.au/jn/punkshell)
as a deployment management and documentation tool\.
# <a name='keywords'></a>KEYWORDS
[punk](\.\./\.\./index\.md\#punk), [repl](\.\./\.\./index\.md\#repl),
[shell](\.\./\.\./index\.md\#shell)
# <a name='category'></a>CATEGORY
shell

21
src/embedded/md/doc/files/punk/_module_cap-0.1.0.tm.md

@ -1,8 +1,8 @@
[//000000001]: # (punk::cap \- punk capabilities plugin system)
[//000000001]: # (punkshell\_module\_punk::cap \- punk capabilities plugin system)
[//000000002]: # (Generated from file '\_module\_cap\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2023 JMNoble \- BSD licensed)
[//000000004]: # (punk::cap\(0\) 0\.1\.0 doc "punk capabilities plugin system")
[//000000004]: # (punkshell\_module\_punk::cap\(0\) 0\.1\.0 doc "punk capabilities plugin system")
<hr> [ <a href="../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../toc.md">Table Of Contents</a> &#124; <a
@ -10,7 +10,7 @@ href="../../../index.md">Keyword Index</a> ] <hr>
# NAME
punk::cap \- capability provider and handler plugin system
punkshell\_module\_punk::cap \- capability provider and handler plugin system
# <a name='toc'></a>Table Of Contents
@ -36,6 +36,8 @@ punk::cap \- capability provider and handler plugin system
- [Namespace punk::cap::capsystem](#subsection5)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
@ -61,10 +63,14 @@ package require punk::cap
punk::cap provides management of named capabilities and the provider packages
and handler packages that implement a pluggable capability\.
see also [tcllib
pluginmgr](https://core\.tcl\-lang\.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr\.md)
for an alternative which uses safe interpreters
## <a name='subsection1'></a>Concepts
A *capability* may be something like providing a folder of files, or just a
data dictionary, and/or an API
A *[capability](\.\./\.\./\.\./index\.md\#capability)* may be something like
providing a folder of files, or just a data dictionary, and/or an API
*capability handler* \- a package/namespace which may provide validation and
standardised ways of looking up provider data registered \(or not\) using
@ -264,6 +270,11 @@ they are here to keep the base API simple\.
Internal functions used to communicate between punk::cap and capability handlers
# <a name='keywords'></a>KEYWORDS
[capability](\.\./\.\./\.\./index\.md\#capability),
[module](\.\./\.\./\.\./index\.md\#module), [plugin](\.\./\.\./\.\./index\.md\#plugin)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2023 JMNoble \- BSD licensed

13
src/embedded/md/doc/files/punk/_module_path-0.1.0.tm.md

@ -1,8 +1,8 @@
[//000000001]: # (punk::path \- punk path filesystem utils)
[//000000001]: # (punkshell\_module\_punk::path \- punk path filesystem utils)
[//000000002]: # (Generated from file '\_module\_path\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2023)
[//000000004]: # (punk::path\(0\) 0\.1\.0 doc "punk path filesystem utils")
[//000000004]: # (punkshell\_module\_punk::path\(0\) 0\.1\.0 doc "punk path filesystem utils")
<hr> [ <a href="../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../toc.md">Table Of Contents</a> &#124; <a
@ -10,7 +10,7 @@ href="../../../index.md">Keyword Index</a> ] <hr>
# NAME
punk::path \- Filesystem path utilities
punkshell\_module\_punk::path \- Filesystem path utilities
# <a name='toc'></a>Table Of Contents
@ -38,6 +38,8 @@ punk::path \- Filesystem path utilities
- [Namespace punk::path::system](#subsection6)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
@ -171,6 +173,11 @@ Secondary functions that are part of the API
## <a name='subsection6'></a>Namespace punk::path::system
# <a name='keywords'></a>KEYWORDS
[filesystem](\.\./\.\./\.\./index\.md\#filesystem),
[module](\.\./\.\./\.\./index\.md\#module), [path](\.\./\.\./\.\./index\.md\#path)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2023

41
src/embedded/md/doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md

@ -1,8 +1,8 @@
[//000000001]: # (punk::mix::commandset::project \- pmix CLI commandset \- project)
[//000000001]: # (punkshell\_module\_punk::mix::commandset::project \- pmix CLI commandset \- project)
[//000000002]: # (Generated from file '\_module\_project\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2023)
[//000000004]: # (punk::mix::commandset::project\(0\) 0\.1\.0 doc "pmix CLI commandset \- project")
[//000000004]: # (punkshell\_module\_punk::mix::commandset::project\(0\) 0\.1\.0 doc "pmix CLI commandset \- project")
<hr> [ <a href="../../../../../toc.md">Main Table Of Contents</a> &#124;
<a href="../../../../toc.md">Table Of Contents</a> &#124; <a
@ -10,7 +10,7 @@ href="../../../../../index.md">Keyword Index</a> ] <hr>
# NAME
punk::mix::commandset::project \- pmix commandset \- project
punkshell\_module\_punk::mix::commandset::project \- pmix commandset \- project
# <a name='toc'></a>Table Of Contents
@ -30,6 +30,9 @@ punk::mix::commandset::project \- pmix commandset \- project
- [Namespace punk::mix::commandset::project](#subsection3)
- [Namespace
punk::mix::commandset::project::collection](#subsection4)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
@ -37,6 +40,7 @@ punk::mix::commandset::project \- pmix commandset \- project
package require punk::mix::commandset::project
[__new__ *newprojectpath\_or\_name* ?args?](#1)
[__\_default__ *glob* ?option value\.\.\.?](#2)
# <a name='description'></a>DESCRIPTION
@ -66,7 +70,8 @@ The above results in the availability of the ensemble command: ::myproject::cli
project\.new, which is implemented in ::punk::mix::commandset::project::new
Similarly, procs under ::punk::mix::commandset::project::collection will be
available as subcommands of the ensemble as projects\.<procname>
available as subcommands of the ensemble as <ensemblecommand>
projects\.<procname>
## <a name='subsection1'></a>Concepts
@ -97,6 +102,34 @@ core commandset functions for punk::mix::commandset::project
new project structure \- may be dedicated to one module, or contain many\.
create minimal folder structure only by specifying in args: \-modules \{\}
## <a name='subsection4'></a>Namespace punk::mix::commandset::project::collection
commandset functions for operating with multiple projects\.
It would usually be imported with the prefix "projects" and separator "\." to
result in commands such as: <ensemblecommand> projects\.detail
- <a name='2'></a>__\_default__ *glob* ?option value\.\.\.?
List projects under fossil management, showing fossil db location and number
of checkouts
The glob argument is optional unless option/value pairs are also supplied,
in which case \* should be explicitly supplied
glob restricts output based on the name of the fossil db file e\.g s\* for all
projects beginning with s
The \_default function is made available in the ensemble by the name of the
prefix used when importing the commandset\.
e\.g
punk::overlay::import\_commandset projects \.
::punk::mix::commandset::project::collection
Will result in the command being available as <ensemblecommand> projects
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2023

12
src/embedded/md/doc/toc.md

@ -3,10 +3,14 @@
# Table Of Contents \-\- doc
- [punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) capability provider and handler plugin system
- [punkshell](doc/files/main\.md) punkshell \- Core
- [punk::mix::commandset::project](doc/files/punk/mix/commandset/\_module\_project\-0\.1\.0\.tm\.md) pmix commandset \- project
- [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes
- [punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities
- [punkshell\_\_project\_intro](doc/files/project\_intro\.md) Introduction to punkshell
- [punkshell](doc/files/main\.md) punkshell \- Core
- [punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) capability provider and handler plugin system
- [punkshell\_module\_punk::mix::commandset::project](doc/files/punk/mix/commandset/\_module\_project\-0\.1\.0\.tm\.md) pmix commandset \- project
- [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities

32
src/embedded/md/index.md

@ -5,26 +5,50 @@
----
[P](#cP) &#183; [R](#cR) &#183; [S](#cS)
[C](#cC) &#183; [F](#cF) &#183; [M](#cM) &#183; [P](#cP) &#183; [R](#cR) &#183; [S](#cS)
----
#### <a name='cC'></a>Keywords: C
|||
|---|---|
|<a name='capability'></a>capability|[punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md)|
|<a name='changelog'></a>changelog|[punkshell\_\_project\_changes](doc/files/project\_changes\.md)|
#### <a name='cF'></a>Keywords: F
|||
|---|---|
|<a name='filesystem'></a>filesystem|[punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md)|
#### <a name='cM'></a>Keywords: M
|||
|---|---|
|<a name='module'></a>module|[punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md)|
#### <a name='cP'></a>Keywords: P
|||
|---|---|
|<a name='punk'></a>punk|[punkshell](doc/files/main\.md)|
|<a name='path'></a>path|[punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md)|
|<a name='plugin'></a>plugin|[punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md)|
|<a name='punk'></a>punk|[punkshell](doc/files/main\.md) &#183; [punkshell\_\_project\_changes](doc/files/project\_changes\.md) &#183; [punkshell\_\_project\_intro](doc/files/project\_intro\.md)|
#### <a name='cR'></a>Keywords: R
|||
|---|---|
|<a name='repl'></a>repl|[punkshell](doc/files/main\.md)|
|<a name='repl'></a>repl|[punkshell](doc/files/main\.md) &#183; [punkshell\_\_project\_changes](doc/files/project\_changes\.md) &#183; [punkshell\_\_project\_intro](doc/files/project\_intro\.md)|
#### <a name='cS'></a>Keywords: S
|||
|---|---|
|<a name='shell'></a>shell|[punkshell](doc/files/main\.md)|
|<a name='shell'></a>shell|[punkshell](doc/files/main\.md) &#183; [punkshell\_\_project\_changes](doc/files/project\_changes\.md) &#183; [punkshell\_\_project\_intro](doc/files/project\_intro\.md)|

12
src/embedded/md/toc.md

@ -3,10 +3,14 @@
# Table Of Contents \-\- doc
- [punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) capability provider and handler plugin system
- [punkshell](doc/files/main\.md) punkshell \- Core
- [punk::mix::commandset::project](doc/files/punk/mix/commandset/\_module\_project\-0\.1\.0\.tm\.md) pmix commandset \- project
- [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes
- [punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities
- [punkshell\_\_project\_intro](doc/files/project\_intro\.md) Introduction to punkshell
- [punkshell](doc/files/main\.md) punkshell \- Core
- [punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) capability provider and handler plugin system
- [punkshell\_module\_punk::mix::commandset::project](doc/files/punk/mix/commandset/\_module\_project\-0\.1\.0\.tm\.md) pmix commandset \- project
- [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities

8
src/embedded/www/.doc/tocdoc

@ -1,6 +1,8 @@
[toc_begin {Table Of Contents} doc]
[item doc/files/punk/_module_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project {pmix commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.html punk::path {Filesystem path utilities}]
[item doc/files/main.html punkshell {punkshell - Core}]
[item doc/files/project_changes.html punkshell__project_changes {punkshell Changes}]
[item doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}]
[item doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap {capability provider and handler plugin system}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {pmix commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}]
[toc_end]

2
src/embedded/www/.idx

@ -1 +1 @@
{shell {{doc/files/main.html punkshell}} punk {{doc/files/main.html punkshell}} repl {{doc/files/main.html punkshell}}} {{repl doc/files/main.html punkshell} . {shell doc/files/main.html punkshell} . {punk doc/files/main.html punkshell} .} 3 {shell shell punk punk repl repl}
{shell {{doc/files/project_intro.html punkshell__project_intro} {doc/files/project_changes.html punkshell__project_changes} {doc/files/main.html punkshell}} changelog {{doc/files/project_changes.html punkshell__project_changes}} filesystem {{doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path}} path {{doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path}} capability {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap}} module {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap} {doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path}} punk {{doc/files/project_intro.html punkshell__project_intro} {doc/files/project_changes.html punkshell__project_changes} {doc/files/main.html punkshell}} plugin {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap}} repl {{doc/files/project_intro.html punkshell__project_intro} {doc/files/project_changes.html punkshell__project_changes} {doc/files/main.html punkshell}}} {{repl doc/files/main.html punkshell} . {punk doc/files/project_intro.html punkshell__project_intro} . {capability doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap} . {changelog doc/files/project_changes.html punkshell__project_changes} . {shell doc/files/project_changes.html punkshell__project_changes} . {shell doc/files/main.html punkshell} . {repl doc/files/project_intro.html punkshell__project_intro} . {module doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap} . {plugin doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap} . {filesystem doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path} . {path doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path} . {module doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path} . {punk doc/files/project_changes.html punkshell__project_changes} . {shell doc/files/project_intro.html punkshell__project_intro} . {punk doc/files/main.html punkshell} . {repl doc/files/project_changes.html punkshell__project_changes} .} 9 {shell shell changelog changelog filesystem filesystem path path capability capability module module punk punk plugin plugin repl repl}

2
src/embedded/www/.toc

@ -1 +1 @@
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.html punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_path-0.1.0.tm.html punk::path {Filesystem path utilities}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.html punkshell {punkshell - Core}}}}
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}} {doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}} {doc/files/project_changes.html punkshell__project_changes {punkshell Changes}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {pmix commandset - project}} {doc/files/main.html punkshell {punkshell - Core}}}}

2
src/embedded/www/.xrf

@ -1 +1 @@
sa,punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.html punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html repl {index.html repl} kw,punk {index.html punk} punkshell(n) doc/files/main.html sa,punk::cap doc/files/punk/_module_cap-0.1.0.tm.html {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.html punkshell doc/files/main.html sa,punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html sa,punk::path doc/files/punk/_module_path-0.1.0.tm.html punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html shell {index.html shell} kw,repl {index.html repl} sa,punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html sa,punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html {punkshell - Core} doc/files/main.html {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html sa,punkshell(n) doc/files/main.html punk::cap doc/files/punk/_module_cap-0.1.0.tm.html sa,punkshell doc/files/main.html kw,shell {index.html shell} punk {index.html punk} punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html punk::path doc/files/punk/_module_path-0.1.0.tm.html
kw,capability {index.html capability} punkshell_module_punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html sa,punkshell_module_punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html {punkshell Changes} doc/files/project_changes.html {Introduction to punkshell} doc/files/project_intro.html punkshell_module_punk::mix::commandset::project(0) doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html sa,punkshell(n) doc/files/main.html filesystem {index.html filesystem} sa,punkshell doc/files/main.html kw,shell {index.html shell} sa,punkshell_module_punk::cap doc/files/punk/_module_cap-0.1.0.tm.html sa,punkshell_module_punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html sa,punkshell__project_changes(n) doc/files/project_changes.html kw,path {index.html path} kw,module {index.html module} punkshell(n) doc/files/main.html kw,plugin {index.html plugin} punkshell doc/files/main.html punkshell_module_punk::cap doc/files/punk/_module_cap-0.1.0.tm.html changelog {index.html changelog} punkshell_module_punk::cap(0) doc/files/punk/_module_cap-0.1.0.tm.html punkshell__project_changes(n) doc/files/project_changes.html sa,punkshell__project_changes doc/files/project_changes.html path {index.html path} sa,punkshell_module_punk::path doc/files/punk/_module_path-0.1.0.tm.html punkshell__project_changes doc/files/project_changes.html kw,filesystem {index.html filesystem} sa,punkshell_module_punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html shell {index.html shell} punkshell_module_punk::path doc/files/punk/_module_path-0.1.0.tm.html kw,repl {index.html repl} capability {index.html capability} punkshell_module_punk::mix::commandset::project doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html {punkshell - Core} doc/files/main.html {pmix commandset - project} doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html {capability provider and handler plugin system} doc/files/punk/_module_cap-0.1.0.tm.html repl {index.html repl} kw,punk {index.html punk} sa,punkshell__project_intro(n) doc/files/project_intro.html sa,punkshell__project_intro doc/files/project_intro.html {Filesystem path utilities} doc/files/punk/_module_path-0.1.0.tm.html sa,punkshell_module_punk::path(0) doc/files/punk/_module_path-0.1.0.tm.html punkshell__project_intro(n) doc/files/project_intro.html punkshell__project_intro doc/files/project_intro.html kw,changelog {index.html changelog} punk {index.html punk} module {index.html module} plugin {index.html plugin}

6
src/embedded/www/doc/files/main.html

@ -1,5 +1,5 @@
<!DOCTYPE html><html><head>
<title>punkshell - punkshell - a Tcl </title>
<title>punkshell - punkshell - a Tcl project</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
@ -101,7 +101,7 @@
&#124; <a href="../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punkshell(n) 1 doc &quot;punkshell - a Tcl &quot;</h1>
<h1 class="doctools_title">punkshell(n) 1 doc &quot;punkshell - a Tcl project&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punkshell - punkshell - Core</p>
</div>
@ -123,7 +123,7 @@
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>Welcome to the punkshell project.</p>
<p>Please read the document <i class="term">punkshell - Introduction to punkshell</i>,
<p>Please read the document <i class="term"><a href="project_intro.html">Introduction to punkshell</a></i>,
if you have not done so already, to get an overview of the whole system.</p>
<p>This document is the reference to commands and modules provided by punkshell</p>
</div>

169
src/embedded/www/doc/files/project_changes.html

@ -0,0 +1,169 @@
<!DOCTYPE html><html><head>
<title>punkshell__project_changes - punkshell - a Tcl project</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file 'project_changes.man' by tcllib/doctools with format 'html'
-->
<!-- punkshell__project_changes.n
-->
<body><hr> [
<a href="../../toc.html">Main Table Of Contents</a>
&#124; <a href="../toc.html">Table Of Contents</a>
&#124; <a href="../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punkshell__project_changes(n) 8 doc &quot;punkshell - a Tcl project&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punkshell__project_changes - punkshell Changes</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Changes</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Changes for version 0.1</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">Bugs, Ideas, Feedback</a></li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#category">Category</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">Tcl 8.6</b></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>Welcome to the punkshell project.</p>
<p>This document provides an overview of the changes <b class="package"><a href="main.html">punkshell</a></b>
underwent from version to version.</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Changes</a></h2>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Changes for version 0.1</a></h3>
<p>This release 0.1 of project punkshell</p>
<p>Summary</p>
<ol class="doctools_enumerated">
<li><p>feature 1</p></li>
<li><p>feature 2</p></li>
</ol>
<p>In detail:</p>
<ol class="doctools_enumerated">
<li><p>punkshell requires Tcl 8.6 or higher. Tcl 8.5 or less is not
supported.</p></li>
<li></li>
</ol>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">Bugs, Ideas, Feedback</a></h2>
<p>This document, and the package it describes, will undoubtedly contain
bugs and other problems.
Please report such at the
<a href="https://gitea1.intx.com.au/jn/punkshell/issues">punkshell tracker</a>.
Please also report any ideas for enhancements you may have for either
package and/or documentation.
Contact: <a href="mailto:julian+punkshell@precisium.com.au">julian+punkshell@precisium.com.au</a></p>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../index.html#changelog">changelog</a>, <a href="../../index.html#punk">punk</a>, <a href="../../index.html#repl">repl</a>, <a href="../../index.html#shell">shell</a></p>
</div>
<div id="category" class="doctools_section"><h2><a name="category">Category</a></h2>
<p>changelog</p>
</div>
</div></body></html>

145
src/embedded/www/doc/files/project_intro.html

@ -0,0 +1,145 @@
<!DOCTYPE html><html><head>
<title>punkshell__project_intro - punkshell - a Tcl project</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file 'project_intro.man' by tcllib/doctools with format 'html'
-->
<!-- punkshell__project_intro.n
-->
<body><hr> [
<a href="../../toc.html">Main Table Of Contents</a>
&#124; <a href="../toc.html">Table Of Contents</a>
&#124; <a href="../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punkshell__project_intro(n) 8 doc &quot;punkshell - a Tcl project&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punkshell__project_intro - Introduction to punkshell</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Bugs, Ideas, Feedback</a></li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#category">Category</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">Tcl 8.6</b></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>Welcome to the punkshell project.</p>
<p>Introduction to punkshell</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Bugs, Ideas, Feedback</a></h2>
<p>This document, and the package it describes, will undoubtedly contain
bugs and other problems.
Please report such at the
<a href="https://gitea1.intx.com.au/jn/punkshell/issues">punkshell tracker</a>.
Please also report any ideas for enhancements you may have for either
package and/or documentation.
Contact: <a href="mailto:julian+punkshell@precisium.com.au">julian+punkshell@precisium.com.au</a></p>
<p>This project uses <a href="https://www.gitea1.intx.com.au/jn/punkshell">PunkShell</a> as a deployment management and documentation tool.</p>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../index.html#punk">punk</a>, <a href="../../index.html#repl">repl</a>, <a href="../../index.html#shell">shell</a></p>
</div>
<div id="category" class="doctools_section"><h2><a name="category">Category</a></h2>
<p>shell</p>
</div>
</div></body></html>

15
src/embedded/www/doc/files/punk/_module_cap-0.1.0.tm.html

@ -1,5 +1,5 @@
<!DOCTYPE html><html><head>
<title>punk::cap - punk capabilities plugin system</title>
<title>punkshell_module_punk::cap - punk capabilities plugin system</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
@ -95,7 +95,7 @@
-->
<!-- Copyright &amp;copy; 2023 JMNoble - BSD licensed
-->
<!-- punk::cap.0
<!-- punkshell_module_punk::cap.0
-->
<body><hr> [
<a href="../../../toc.html">Main Table Of Contents</a>
@ -103,9 +103,9 @@
&#124; <a href="../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punk::cap(0) 0.1.0 doc &quot;punk capabilities plugin system&quot;</h1>
<h1 class="doctools_title">punkshell_module_punk::cap(0) 0.1.0 doc &quot;punk capabilities plugin system&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punk::cap - capability provider and handler plugin system</p>
<p>punkshell_module_punk::cap - capability provider and handler plugin system</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
@ -129,6 +129,7 @@
<li class="doctools_subsection"><a href="#subsection5">Namespace punk::cap::capsystem</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
@ -156,8 +157,9 @@
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.</p>
<p>see also <a href="https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md">tcllib pluginmgr</a> for an alternative which uses safe interpreters</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>A <i class="term">capability</i> may be something like providing a folder of files, or just a data dictionary, and/or an API</p>
<p>A <i class="term"><a href="../../../index.html#capability">capability</a></i> may be something like providing a folder of files, or just a data dictionary, and/or an API</p>
<p><i class="term">capability handler</i> - a package/namespace which may provide validation and standardised ways of looking up provider data
registered (or not) using register_capabilityname &lt;capname&gt; &lt;capnamespace&gt;</p>
<p><i class="term">capability provider</i> - a package which registers as providing one or more capablities.</p>
@ -299,6 +301,9 @@ In some cases the preference/loading order may be inapplicable/irrelevant to a p
</dl>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../index.html#capability">capability</a>, <a href="../../../index.html#module">module</a>, <a href="../../../index.html#plugin">plugin</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2023 JMNoble - BSD licensed</p>
</div>

12
src/embedded/www/doc/files/punk/_module_path-0.1.0.tm.html

@ -1,5 +1,5 @@
<!DOCTYPE html><html><head>
<title>punk::path - punk path filesystem utils</title>
<title>punkshell_module_punk::path - punk path filesystem utils</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
@ -95,7 +95,7 @@
-->
<!-- Copyright &amp;copy; 2023
-->
<!-- punk::path.0
<!-- punkshell_module_punk::path.0
-->
<body><hr> [
<a href="../../../toc.html">Main Table Of Contents</a>
@ -103,9 +103,9 @@
&#124; <a href="../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punk::path(0) 0.1.0 doc &quot;punk path filesystem utils&quot;</h1>
<h1 class="doctools_title">punkshell_module_punk::path(0) 0.1.0 doc &quot;punk path filesystem utils&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punk::path - Filesystem path utilities</p>
<p>punkshell_module_punk::path - Filesystem path utilities</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
@ -130,6 +130,7 @@
<li class="doctools_subsection"><a href="#subsection6">Namespace punk::path::system</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
@ -231,6 +232,9 @@ no natsorting - so order is dependent on filesystem</p></dd>
<p>Internal functions that are not part of the API</p>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../index.html#filesystem">filesystem</a>, <a href="../../../index.html#module">module</a>, <a href="../../../index.html#path">path</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2023</p>
</div>

26
src/embedded/www/doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html

@ -1,5 +1,5 @@
<!DOCTYPE html><html><head>
<title>punk::mix::commandset::project - pmix CLI commandset - project</title>
<title>punkshell_module_punk::mix::commandset::project - pmix CLI commandset - project</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
@ -95,7 +95,7 @@
-->
<!-- Copyright &amp;copy; 2023
-->
<!-- punk::mix::commandset::project.0
<!-- punkshell_module_punk::mix::commandset::project.0
-->
<body><hr> [
<a href="../../../../../toc.html">Main Table Of Contents</a>
@ -103,9 +103,9 @@
&#124; <a href="../../../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">punk::mix::commandset::project(0) 0.1.0 doc &quot;pmix CLI commandset - project&quot;</h1>
<h1 class="doctools_title">punkshell_module_punk::mix::commandset::project(0) 0.1.0 doc &quot;pmix CLI commandset - project&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>punk::mix::commandset::project - pmix commandset - project</p>
<p>punkshell_module_punk::mix::commandset::project - pmix commandset - project</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
@ -121,6 +121,7 @@
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::mix::commandset::project</a></li>
<li class="doctools_subsection"><a href="#subsection4">Namespace punk::mix::commandset::project::collection</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
@ -133,6 +134,7 @@
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="function">new</b> <i class="arg">newprojectpath_or_name</i> <span class="opt">?args?</span></a></li>
<li><a href="#2"><b class="function">_default</b> <i class="arg">glob</i> <span class="opt">?option value...?</span></a></li>
</ul>
</div>
</div>
@ -154,7 +156,7 @@
<p>Where the . in the above example is the prefix/command separator</p>
<p>The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.</p>
<p>The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new</p>
<p>Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.&lt;procname&gt;</p>
<p>Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as &lt;ensemblecommand&gt; projects.&lt;procname&gt;</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>see punk::overlay</p>
</div>
@ -179,6 +181,20 @@
create minimal folder structure only by specifying in args: -modules {}</p></dd>
</dl>
</div>
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace punk::mix::commandset::project::collection</a></h3>
<p>commandset functions for operating with multiple projects.</p>
<p>It would usually be imported with the prefix &quot;projects&quot; and separator &quot;.&quot; to result in commands such as: &lt;ensemblecommand&gt; projects.detail</p>
<dl class="doctools_definitions">
<dt><a name="2"><b class="function">_default</b> <i class="arg">glob</i> <span class="opt">?option value...?</span></a></dt>
<dd><p>List projects under fossil management, showing fossil db location and number of checkouts</p>
<p>The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied</p>
<p>glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s</p>
<p>The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.</p>
<p>e.g</p>
<p>punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection</p>
<p>Will result in the command being available as &lt;ensemblecommand&gt; projects</p></dd>
</dl>
</div>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2023</p>

24
src/embedded/www/doc/toc.html

@ -13,20 +13,28 @@
<hr><dl><dt><h2>doc</h2></dt><dd>
<table class="#doctools_toc">
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punk_cap'><a href="files/punk/_module_cap-0.1.0.tm.html">punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td>
<td class="#doctools_tocleft" ><a name='punkshell'><a href="files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punk_mix_commandset_project'><a href="files/punk/mix/commandset/_module_project-0.1.0.tm.html">punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">pmix commandset - project</td>
<td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="files/project_changes.html">punkshell__project_changes</a></td>
<td class="#doctools_tocright">punkshell Changes</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punk_path'><a href="files/punk/_module_path-0.1.0.tm.html">punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td>
<td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="files/project_intro.html">punkshell__project_intro</a></td>
<td class="#doctools_tocright">Introduction to punkshell</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell'><a href="files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td>
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">pmix commandset - project</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td>
</tr>
</table>
</dd></dl><hr></body></html>

47
src/embedded/www/index.html

@ -13,16 +13,55 @@
] <hr>
<h3> Keyword Index </h3>
<hr><div class="#doctools_idxnav">
<a href="#cP"> P </a> &#183; <a href="#cR"> R </a> &#183; <a href="#cS"> S </a>
<a href="#cC"> C </a> &#183; <a href="#cF"> F </a> &#183; <a href="#cM"> M </a> &#183; <a href="#cP"> P </a> &#183; <a href="#cR"> R </a> &#183; <a href="#cS"> S </a>
</div>
<hr><table class="#doctools_idx" width="100%">
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cC">Keywords: C</a>
</th></tr>
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="capability"> capability </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a>
</td></tr>
<tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="changelog"> changelog </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/project_changes.html"> punkshell__project_changes </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cF">Keywords: F</a>
</th></tr>
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="filesystem"> filesystem </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cM">Keywords: M</a>
</th></tr>
<tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="module"> module </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a> &#183; <a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cP">Keywords: P</a>
</th></tr>
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="path"> path </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a>
</td></tr>
<tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="plugin"> plugin </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a>
</td></tr>
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="punk"> punk </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a>
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cR">Keywords: R</a>
@ -30,7 +69,7 @@
<tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="repl"> repl </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a>
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cS">Keywords: S</a>
@ -38,7 +77,7 @@
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="shell"> shell </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a>
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
</td></tr>
</table>
</body></html>

24
src/embedded/www/toc.html

@ -13,20 +13,28 @@
<hr><dl><dt><h2>doc</h2></dt><dd>
<table class="#doctools_toc">
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punk_cap'><a href="doc/files/punk/_module_cap-0.1.0.tm.html">punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td>
<td class="#doctools_tocleft" ><a name='punkshell'><a href="doc/files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punk_mix_commandset_project'><a href="doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html">punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">pmix commandset - project</td>
<td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="doc/files/project_changes.html">punkshell__project_changes</a></td>
<td class="#doctools_tocright">punkshell Changes</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punk_path'><a href="doc/files/punk/_module_path-0.1.0.tm.html">punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td>
<td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="doc/files/project_intro.html">punkshell__project_intro</a></td>
<td class="#doctools_tocright">Introduction to punkshell</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell'><a href="doc/files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td>
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="doc/files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">pmix commandset - project</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="doc/files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td>
</tr>
</table>
</dd></dl><hr></body></html>

4
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/cap-0.1.0.tm

@ -15,14 +15,16 @@
#*** !doctools
#[manpage_begin punk::cap 0 0.1.0]
#[manpage_begin punkshell_module_punk::cap 0 0.1.0]
#[copyright "2023 JMNoble - BSD licensed"]
#[titledesc {capability provider and handler plugin system}]
#[moddesc {punk capabilities plugin system}]
#[require punk::cap]
#[description]
#[keywords module capability plugin]
#[section Overview]
#[para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.
#[para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters
#[subsection Concepts]
#[para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API
#

71
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/docgen-0.1.0.tm

@ -0,0 +1,71 @@
# -*- tcl -*
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::docgen 0.1.0
# Meta platform tcl
# Meta license BSD
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
##e.g package require frobz
package require punk::repo
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::docgen {
proc get_doctools_comments {fname} {
#does no validation of doctools commands
#existence of string match #\**!doctools is taken as evidence enough that the file has inline doctools - review
if {![file exists $fname]} {
error "get_doctools_comments file '$fname' not found"
}
set fd [open $fname r]
set data [read $fd]
close $fd
if {![string match "*#\**!doctools*" $data]} {
return
}
set data [string map [list \r\n \n] $data]
set in_doctools 0
set doctools ""
foreach ln [split $data \n] {
set ln [string trim $ln]
if {$in_doctools && [string index $ln 0] != "#"} {
set in_doctools 0
} elseif {[string range $ln 0 1] == "#*"} {
#todo - process doctools ordering hints in tail of line
set in_doctools 1
} elseif {$in_doctools} {
append doctools [string range $ln 1 end] \n
}
}
return $doctools
}
#todo - proc autogen_doctools_comments {fname} {}
# - will probably need to use something like parsetcl - as we won't be able to reliably source in an interp without side-effects and use info body etc.
# - mechanism will be to autodocument namespaces, procs, methods where no #*** doctools indication present - but use existing doctools comments for that particular item if it is present.
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::docgen [namespace eval punk::docgen {
variable pkg punk::docgen
variable version
set version 0.1.0
}]
return

153
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/du-0.1.0.tm

@ -837,7 +837,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -921,48 +921,10 @@ namespace eval punk::du {
set dirs [struct::set difference [concat $hdirs $dirs[unset dirs]] [concat $links [list [file join $folderpath .] [file join $folderpath ..] ]]]
set links [lsort -unique [concat $links $hlinks]]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
#----
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
if {"windows" eq $::tcl_platform(platform)} {
@ -979,7 +941,7 @@ namespace eval punk::du {
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
proc du_dirlisting_tclvfs {folderpath args} {
@ -995,7 +957,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1048,55 +1010,14 @@ namespace eval punk::du {
#nested vfs mount.. REVIEW - does anything need special handling?
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
#we can halve the number of round trips on unix-like systems, where 'hidden' always corresponds to dotted files
@ -1107,7 +1028,7 @@ namespace eval punk::du {
-with_times 0\
]
set errors [dict create]
dict lappend errors $folderpath "metdata support incomplete - prefer du_dirlisting_generic"
dict lappend errors $folderpath "metadata support incomplete - prefer du_dirlisting_generic"
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob]
@ -1115,7 +1036,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1165,14 +1086,64 @@ namespace eval punk::du {
set files [struct::set difference $files[unset files] $links]
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes {} times {} flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
}
#return fsizes,allsizes,alltimes metadata in same order as files,dirs,links lists - if specified in sized_types
proc du_get_metadata_lists {sized_types timed_types files dirs links} {
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
#subst with na if empty?
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
#todo - fix . The list lengths will presumably match but have empty values if failed to stat
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
return [dict create fsizes $fsizes allsizes $allsizes alltimes $alltimes]
}
proc du_lit value {

4
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/cli-0.3.tm

@ -867,6 +867,7 @@ namespace eval punk::mix::cli {
::kettle option set @srcscript $path
::kettle option set @srcdir [file dirname $path]
::kettle option set @goals $goals
#load standard recipes as listed in build.tcl
::source $path
puts stderr "recipes: [::kettle recipe names]"
::kettle recipe run {*}[::kettle option get @goals]
@ -884,6 +885,9 @@ namespace eval punk::mix::cli {
}
}
proc kettle_punk_recipes {} {
set txtdst ...
}
}
}

7
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm

@ -173,9 +173,12 @@ namespace eval punk::mix::commandset::doc {
return $result
}
set original_wd [pwd]
cd $projectdir/src
set docroot $projectdir/src/doc
cd $docroot
dtplite validate $docroot
punk::mix::cli::lib::kettle_call lib validate-doc
#punk::mix::cli::lib::kettle_call lib validate-doc
cd $original_wd
}

2
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -273,7 +273,7 @@ namespace eval punk::mix::commandset::module {
set infile_version $build_version
}
set template_filedata [string map [list %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set template_filedata [string map [list %project% $projectname %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set modulefile $modulefolder/${moduletail}-$infile_version.tm
if {[file exists $modulefile]} {

61
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm

@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punk::mix::commandset::project 0 0.1.0]
#[manpage_begin punkshell_module_punk::mix::commandset::project 0 0.1.0]
#[copyright "2023"]
#[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}]
#[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}]
@ -44,7 +44,7 @@
#[para] Where the . in the above example is the prefix/command separator
#[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.
#[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname>
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects.<procname>
#[para]
#[subsection Concepts]
#[para] see punk::overlay
@ -498,11 +498,25 @@ namespace eval punk::mix::commandset::project {
#[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}]
namespace eval collection {
#*** !doctools
#[subsection {Namespace punk::mix::commandset::project::collection}]
#[para] commandset functions for operating with multiple projects.
#[para] It would usually be imported with the prefix "projects" and separator "." to result in commands such as: <ensemblecommand> projects.detail
#[list_begin definitions]
namespace export *
namespace path [namespace parent]
#e.g imported as 'projects'
proc _default {{glob {}} args} {
#*** !doctools
#[call [fun _default] [arg glob] [opt {option value...}]]
#[para]List projects under fossil management, showing fossil db location and number of checkouts
#[para]The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
#[para]glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s
#[para]The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.
#[para]e.g
#[para] punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection
#[para]Will result in the command being available as <ensemblecommand> projects
package require overtype
set db_projects [lib::get_projects $glob]
set col1items [lsearch -all -inline -index 0 -subindices $db_projects *]
@ -510,7 +524,7 @@ namespace eval punk::mix::commandset::project {
set checkouts [lsearch -all -inline -index 2 -subindices $db_projects *]
set col3items [lmap v $checkouts {llength $v}]
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1items] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -596,7 +610,7 @@ namespace eval punk::mix::commandset::project {
}
}
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1_dbfiles] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -656,15 +670,27 @@ namespace eval punk::mix::commandset::project {
proc work {{glob {}} args} {
package require sqlite3
set db_projects [lib::get_projects $glob]
if {[llength $db_projects] == 0} {
puts stderr "::punk::mix::commandset::project::work No Repo DB name matches found for '$glob'"
return ""
}
#list of lists of the form:
#{fosdb fname workdirlist}
set defaults [dict create\
-cd 0\
-detail "\uFFFF"\
]
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- ---
set opt_cd [dict get $opts -cd]
# -- --- --- --- --- --- ---
set opt_detail [dict get $opts -detail]
set opt_detail_explicit_zero 1 ;#default assumption only
if {$opt_detail eq "\uFFFF"} {
set opt_detail_explicit_zero 0
set opt_detail 0; #default
}
# -- --- --- --- --- --- ---
set workdir_dict [dict create]
set all_workdirs [list]
foreach pinfo $db_projects {
@ -732,10 +758,17 @@ namespace eval punk::mix::commandset::project {
set col_states [list]
set state_title ""
#if only one set of fossil checkouts in the resultset - retrieve workingdir state for each co
if {[llength [dict keys $fosdb_cache]] == 1} {
puts stderr "Result is a single project - gathering file state for each checkout folder"
#if only one set of fossil checkouts in the resultset and opt_detail is 0 and not explicit - retrieve workingdir state for each co
if {([llength [dict keys $fosdb_cache]] == 1)} {
if {!$opt_detail_explicit_zero} {
set opt_detail 1
}
puts stderr "Result is from a single repo db [dict keys $fosdb_cache]"
}
if {$opt_detail} {
puts stderr "Gathering file state for [llength $workdirs] checkout folder(s). Use -detail 0 to omit file state"
set c_rev [list]
set c_rev_iso [list]
set c_unchanged [list]
set c_changed [list]
set c_new [list]
@ -745,6 +778,7 @@ namespace eval punk::mix::commandset::project {
set wd_state [punk::repo::workingdir_state $wd]
set state_dict [punk::repo::workingdir_state_summary_dict $wd_state]
lappend c_rev [string range [dict get $state_dict revision] 0 9]
lappend c_rev_iso [dict get $state_dict revision_iso8601]
lappend c_unchanged [dict get $state_dict unchanged]
lappend c_changed [dict get $state_dict changed]
lappend c_new [dict get $state_dict new]
@ -756,6 +790,9 @@ namespace eval punk::mix::commandset::project {
set t0 "Revision"
set w0 [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev] {string length $v}]]
set c0 [string repeat " " $w0]
set t0b "Revision iso8601"
set w0b [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev_iso] {string length $v}]]
set c0b [string repeat " " $w0b]
set t1 "Unch"
set w1 [tcl::mathfunc::max {*}[lmap v [concat [list $t1] $c_unchanged] {string length $v}]]
set c1 [string repeat " " $w1]
@ -772,9 +809,9 @@ namespace eval punk::mix::commandset::project {
set w5 [tcl::mathfunc::max {*}[lmap v [concat [list $t5] $c_extra] {string length $v}]]
set c5 [string repeat " " $w5]
set state_title "[overtype::left $c0 $t0] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
set state_title "[overtype::left $c0 $t0] [overtype::left $c0b $t0b] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev iso $c_rev_iso u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::left $c0b $iso] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
}
}
@ -789,7 +826,7 @@ namespace eval punk::mix::commandset::project {
set title1 "Checkout dir"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $workdirs] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "Db name"
set title2 "Repo DB name"
set widest2 [tcl::mathfunc::max {*}[lmap v [concat [list $title2] $col_fnames] {string length $v}]]
set col2 [string repeat " " $widest2]
set title3 "CO dup"
@ -851,6 +888,8 @@ namespace eval punk::mix::commandset::project {
}
return $msg
}
#*** !doctools
#[list_end] [comment {-- end collection namespace definitions --}]
}
namespace eval lib {

73
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm

@ -100,13 +100,18 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the tcl-payload or xxx-payload-pre-tcl site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} {
set defaults [list -askme 1 -template \uFFFF]
set opts [dict merge $defaults $args]
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
set defaults [dict create\
-askme 1\
-outputfolder "\uFFFF"\
-template "\uFFFF"\
]
set known_opts [dict keys $defaults]
dict for {k v} $args {
if {$k ni $known_opts} {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts"
}
}
set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -116,6 +121,17 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
}
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set opt_outputfolder [dict get $opts -outputfolder]
# -- --- --- --- --- --- --- --- --- --- --- ---
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
#first check if relative or absolute path matches a file
@ -124,7 +140,6 @@ namespace eval punk::mix::commandset::scriptwrap {
} else {
set specified_path [file join $startdir $filepath_or_scriptset]
}
set ext [string trim [file extension $filepath_or_scriptset] .]
set allowed_extensions [list wrapconfig tcl ps1 sh bash]
#set allowed_extensions [list tcl]
@ -203,7 +218,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
} else {
if {[file pathtype $something_found] ne "file"} {
if {[file type $something_found] ne "file"} {
puts stderr "Found '$something_found'"
puts stderr "wrap_in_multishell doesn't currently support a directory as the path."
puts stderr $usage
return false
@ -280,11 +296,37 @@ namespace eval punk::mix::commandset::scriptwrap {
}
#todo
#output_file extension depends on the template being used..
if {$opt_outputfolder eq "\uFFFF"} {
#outputfolder not explicitly specified by caller
if {[string length $projectroot]} {
set output_folder [file join $projectroot/bin]
} else {
set output_folder $startdir
}
} else {
if {[file pathtype $opt_outputfolder] eq "relative"} {
if {[string length $projectroot]} {
set output_folder [file join $projectroot $opt_outputfolder]
} else {
set output_folder [file join $startdir $opt_outputfolder]
}
} else {
set output_folder $opt_outputfolder
}
}
if {![file isdirectory $output_folder]} {
error "wrap_in_multishell: output folder '$output_folder' not found. Please ensure target directory exists"
}
set output_file $scriptset.cmd
#todo
#output_file extension may also depend on the template being used.. and/or the .wrapconfig
if {$::tcl_platform(platform) eq "windows"} {
set output_extension cmd
} else {
set output_extension sh
}
set output_file [file join $output_folder $scriptset.$output_extension]
if {[file exists $output_file]} {
error "wrap_in_multishell: target file $output_file already exists.. aborting"
}
@ -308,7 +350,7 @@ namespace eval punk::mix::commandset::scriptwrap {
set list_input_files [list]
if {$process_extensions eq "ALLFOUNDORCONFIGURED"} {
#todo - look for .wrapconfig or all extensions for the scriptset
puts stderr "Sorry - only single input file supported - implementation incomplete"
puts stderr "Sorry - only single input file supported. Supply a file extension or use a .wrapconfig with a single input file for now - implementation incomplete"
return false
} else {
lappend list_input_files $scriptroot/$scriptset.$ext
@ -332,8 +374,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stdout $ln
}
puts stdout "-----------------------------------------------\n"
if {$opt_askme} {
puts stdout "Target for above data is '$output_file'"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
@ -394,6 +436,11 @@ namespace eval punk::mix::commandset::scriptwrap {
puts -nonewline $fdtarget $newscript
close $fdtarget
puts stdout "Wrote script file at $output_file"
#even though chmod might exist on windows - we will leave permissions alone
if {$::tcl_platform(platform) ne "windows"} {
catch {exec chmod +x $output_file}
}
puts stdout "-done-"
return $output_file
}

4
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/ns-0.1.0.tm

@ -1547,6 +1547,7 @@ namespace eval punk::ns {
foreach fullv $varnames {
set v [namespace tail $fullv]
upvar 1 $v var
if {[info exists var]} {
if {$v eq "args"} {
dict set capturevars "prev_args$n" [list var $var]
} else {
@ -1556,6 +1557,9 @@ namespace eval punk::ns {
dict set capturearrs $v [array get var]
}
}
} else {
#A variable can show in the results for 'info vars' (or nsvars) but still not exist. e.g a 'variable x' declaration in the namespace where the variable has never been set
}
}
return [dict create vars $capturevars arrs $capturearrs]
} } [info vars [namespace current]::*] ;#we are relying on info vars ::::* returning same as info vars ::* - a bit hacky (don't want to set any extra vars in the ns)

397
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/path-0.1.0.tm

@ -0,0 +1,397 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::path 0.1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.1.0]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
#[require punk::path]
#[description]
#[keywords module path filesystem]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::path
#[para] Filesystem path utility functions
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::path
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::class {
#*** !doctools
#[subsection {Namespace punk::path::class}]
#[para] class definitions
if {[info commands [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 ---}]
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path {
namespace export *
#variable xyz
#*** !doctools
#[subsection {Namespace punk::path}]
#[para] Core API functions for punk::path
#[list_begin definitions]
proc pathglob_as_re {pathglob} {
#*** !doctools
#[call [fun pathglob_as_re] [arg pathglob]]
#[para] Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure
#[para] ** matches any number of subdirectories.
#[para] e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself)
#[para] e.g /etc/**.txt will match any .txt files at any depth below /etc
#[para] any segment that does not contain ** must match exactly one segment in the path
#[para] e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc
#[para] The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified.
#[para] Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals
#todo - consider whether a way to escape the glob chars ? * is practical - to allow literals ? *
# - would require counting immediately-preceding backslashes
set pats [list]
foreach seg [file split $pathglob] {
if {[string range $seg end end] eq "/"} {
set seg [string range $seg 0 end-1] ;# e.g c:/ -> c: / -> "" so that join at end doesn't double up
}
if {$seg eq "*"} {
lappend pats {[^/]*}
} elseif {$seg eq "**"} {
lappend pats {.*}
} else {
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals
set seg [string map [list . {[.]}] $seg]
if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg]
lappend pats "$pat"
} else {
lappend pats "$seg"
}
}
}
return "^[join $pats /]\$"
}
proc globmatchpath {pathglob path args} {
#*** !doctools
#[call [fun globmatchpath] [arg pathglob] [arg path] [opt {option value...}]]
#[para] Return true if the pathglob matches the path
#[para] see [fun pathglob_as_re] for pathglob description
#[para] Caller must ensure that file separator is forward slash. (e.g use file normalize on windows)
#[para]
#[para] Known options:
#[para] -nocase 0|1 (default 0 - case sensitive)
#[para] If -nocase is not supplied - default to case sensitive *except for driveletter*
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.
set defaults [dict create\
-nocase \uFFFF\
]
set known_opts [dict keys $defaults]
set opts [dict merge $defaults $args]
dict for {k v} $args {
if {$k ni $known_opts} {
error "Unrecognised options $k - known options: $known_opts"
}
}
# -- --- --- --- --- ---
set opt_nocase [dict get $opts -nocase]
set explicit_nocase 1 ;#default to disprove
if {$opt_nocase eq "\uFFFF"} {
set opt_nocase 0
set explicit_nocase 0
}
# -- --- --- --- --- ---
if {$opt_nocase} {
return [regexp -nocase [pathglob_as_re $pathglob] $path]
} else {
set re [pathglob_as_re $pathglob]
if {$explicit_nocase} {
set ismatch [regexp $re $path] ;#explicit -nocase 0 - require exact match of path literals including driveletter
} else {
#caller is using default for -nocase - which indicates case sensitivity - but we have an exception for the driveletter.
set re_segments [file split $re] ;#Note that file split c:/etc gives {c:/ etc} but file split ^c:/etc gives {^c: etc}
set first_seg [lindex $re_segments 0]
if {[regexp {^\^(.{1}):$} $first_seg _match driveletter]} {
#first part of re is like "^c:" i.e a drive letter
set chars [string tolower $driveletter][string toupper $driveletter]
set re [join [concat "^\[$chars\]:" [lrange $re_segments 1 end]] /] ;#rebuild re with case insensitive driveletter only - use join - not file join. file join will misinterpret leading re segment.
}
#puts stderr "-->re: $re"
set ismatch [regexp $re $path]
}
}
return $ismatch
}
#todo - implement treefiles which acts like dirfiles but allows path globbing in the same way as punk::ns::ns/
#then review if treefiles can replace dirfiles or if both should exist (dirfiles can have literal glob chars in path segments - but that is a rare usecase)
proc treefilenames {basepath tailglob args} {
#*** !doctools
#[call [fun treefilenames] [arg basepath] [arg tailglob] [opt {option value...}]]
#basic (glob based) list of filenames matching tailglob - recursive
#no natsorting - so order is dependent on filesystem
set defaults [dict create\
-call-depth-internal 0\
-antiglob_paths {}\
]
set opts [dict merge $defaults $args]
set opt_antiglob_paths [dict get $opts -antiglob_paths]
set CALLDEPTH [dict get $opts -call-depth-internal]
set files [list]
if {$CALLDEPTH == 0} {
if {![file isdirectory $basepath]} {
return [list]
}
}
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $basepath]} {
set skip 1
break
}
}
if {$skip} {
return [list]
}
#todo - account for vfs where matched path could appear to be a directory but is mounted so could be a desired match?
set dirfiles [glob -nocomplain -dir $basepath -type f $tailglob]
lappend files {*}$dirfiles
set dirdirs [glob -nocomplain -dir $basepath -type d *]
foreach dir $dirdirs {
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $dir]} {
set skip 1
break
}
}
if {$skip} {
continue
}
set nextargs [dict merge $args [list -call-depth-internal [incr CALLDEPTH]]]
lappend files {*}[treefilenames $dir $tailglob {*}$nextargs]
}
return $files
}
#maint warning - also in punkcheck
proc relative {reference location} {
#*** !doctools
#[call [fun relative] [arg reference] [arg location]]
#[para] Taking two directory paths, a reference and a location, computes the path
# of the location relative to the reference.
#[list_begin itemized]
#[item]
#[para] Arguments:
# [list_begin arguments]
# [arg_def string reference] The path from which the relative path to location is determined.
# [arg_def string location] The location path which may be above or below the reference path
# [list_end]
#[item]
#[para] Results:
#[para] The relative path of the location to the reference path.
#[para] Will return a single dot "." if the paths are the same
#[item]
#[para] Notes:
#[para] Both paths must be the same type - ie both absolute or both relative
#[para] Case sensitive. ie relative /etc /etC
# will return ../etC
#[para] On windows, the drive-letter component (only) is not case sensitive
#[para] ie relative c:/etc C:/etc returns .
#[para] but relative c:/etc C:/Etc returns ../Etc
#[para] On windows, if the paths are absolute and specifiy different volumes, only the location will be returned.
# ie relative c:/etc d:/etc/blah
# returns d:/etc/blah
#[list_end]
#see also kettle
# Modified copy of ::fileutil::relative (tcllib)
# Adapted to 8.5 ({*}).
#review - check volume info on windows.. UNC paths?
if {[file pathtype $reference] ne [file pathtype $location]} {
return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $reference] vs. [file pathtype $location], ($reference vs. $location)"
}
#avoid normalizing if possible (file normalize *very* expensive on windows)
set do_normalize 0
if {[file pathtype $reference] eq "relative"} {
#if reference is relative so is location
if {[regexp {[.]{2}} [list $reference $location]]} {
set do_normalize 1
}
if {[regexp {[.]/} [list $reference $location]]} {
set do_normalize 1
}
} else {
set do_normalize 1
}
if {$do_normalize} {
set reference [file normalize $reference]
set location [file normalize $location]
}
set save $location
set reference [file split $reference]
set location [file split $location]
while {[lindex $location 0] eq [lindex $reference 0]} {
set location [lrange $location 1 end]
set reference [lrange $reference 1 end]
if {![llength $location]} {break}
}
set location_len [llength $location]
set reference_len [llength $reference]
if {($location_len == 0) && ($reference_len == 0)} {
# Cases:
# (a) reference == location
set location .
} else {
# Cases:
# (b) ref is: ref/sub = sub
# loc is: ref = {}
# (c) ref is: ref = {}
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
incr reference_len -1
}
set location [file join {*}$location]
}
return $location
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::lib {
namespace export *
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::path::lib}]
#[para] Secondary functions that are part of the API
#[list_begin definitions]
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::path::system {
#*** !doctools
#[subsection {Namespace punk::path::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.1.0
}]
return
#*** !doctools
#[manpage_end]

40
src/mixtemplates/layouts/basic/src/bootsupport/modules/punk/repo-0.1.1.tm

@ -314,6 +314,10 @@ namespace eval punk::repo {
# -repotypes is an ordered list - if the closest repo is multi-typed the order will determine which is used.
# This deliberately doesn't allow bypassing a sub-repo to look for a higher-level repo in a repo-nest.
# The theory is that sub-repos shouldn't have their contents directly tracked directly by higher-level repos anyway
#REVIEW - if closest repo is both fossil and git - we only return info for one, with fossil being preferenced
#This may not make sense if we want to allow fossil tracking of projects where git is the primary repotype and fossil is just used to enable us to enumerate projects?
#does a dual git/fossil repo make sense if both are committing??
# see: https://fossil-scm.org/home/doc/trunk/www/inout.wiki for bidirectional sync info
proc workingdir_state {{abspath {}} args} {
set defaults [list\
-repotypes [list fossil git]\
@ -364,6 +368,9 @@ namespace eval punk::repo {
}
set resultdict [dict create repodir $repodir subpath $subpath]
#set defaults in case no supported repotype found
set revision ""
set revision_iso8601 ""
set pathdict [dict create]
if {![llength $repotypes_to_query]} {
@ -384,9 +391,15 @@ namespace eval punk::repo {
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$fossil_cmd status --all --differ --merge $abspath]} fossilstate]} {
error "workingdir_state error: Unable to retrieve workingdir state using fossil. Errormsg: $fossilstate"
}
# line: checkout: fb971...
set revision [lindex [grep {checkout:*} $fossilstate] 0 1]
# line: checkout: fb971... Y-m-d H:M:S TZ
set checkout_info [lindex [grep {checkout:*} $fossilstate] 0] ;#grep returns a list - but it should always be a single match in this case
set revision [lindex $checkout_info 0 1]
#set checkrevision [fossil_revision $abspath]
lassign $checkout_info _key revision revision_ymd revision_hms revision_tz
if {$revision_tz eq "UTC"} {
set revision_tz "+0000" ;#normalize UTC for consistency with git tz output - review - should do date-math if necessary on git and fossil to bring all to +0000 (is fossil always UTC? git )
}
set revision_iso8601 "${revision_ymd}T${revision_hms}${revision_tz}"
dict set resultdict ahead ""
@ -442,6 +455,25 @@ namespace eval punk::repo {
puts stderr "workingdir_state: git revision is (initial) - no file state to gather"
break
}
# -- --- --- --- ---
#could use %ci for ISO8601 data - see git-show manpage, but this will be in timezone of developer's machine - we need it in UTC for comparison to fossil outputs and other devs
set had_TZ 0
if {[info exists ::env(TZ)]} {
set TZ_prev $::env(TZ)
set had_TZ 1
}
set ::env(TZ) "UTC0"
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$git_cmd show -s --date=format-local:%Y:%m:%dT%H:%M:%S+0000 --format=format:%cd -- $abspath]} revision_iso8601]} {
puts stderr "workingdir_state warning: Unable to retrieve workingdir state using git. Errormsg: $gitstate"
}
if {$had_TZ} {
set ::env(TZ) $TZ_prev
} else {
unset ::env(TZ)
}
# -- --- --- --- ---
dict set resultdict ahead ""
dict set resultdict behind ""
set aheadbehind [lindex [grep {# branch.ab *} $gitstate] 0]
@ -525,6 +557,7 @@ namespace eval punk::repo {
}
}
dict set resultdict revision $revision
dict set resultdict revision_iso8601 $revision_iso8601
dict set resultdict paths $pathdict
return $resultdict
}
@ -547,6 +580,7 @@ namespace eval punk::repo {
repodir repodir\
subpath subpath\
revision revision\
revision_iso8601 revision_iso8601\
ahead ahead\
behind behind\
repotype repotype\
@ -590,7 +624,7 @@ namespace eval punk::repo {
}
set filestates [dict values [dict get $repostate paths]]
set path_count_fields [list unchanged changed new missing extra]
set state_fields [list ahead behind repodir subpath repotype revision]
set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601]
set dresult [dict create]
foreach f $state_fields {
dict set dresult $f [dict get $repostate $f]

2
src/mixtemplates/layouts/basic/src/bootsupport/modules/punkcheck-0.1.0.tm

@ -743,7 +743,7 @@ namespace eval punkcheck {
#The files we depended on for the previous record haven't changed themselves - but the list of files has (reduced by one)
proc installfile_add_source_and_fetch_metadata {punkcheck_folder source_relpath file_record} {
if {![lib::is_file_record_inprogress $file_record]} {
error "installfile_add_source_and_fetch_metdata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
error "installfile_add_source_and_fetch_metadata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
}
set ts_start [clock microseconds]
set last_installrecord [lib::file_record_get_last_installrecord $file_record]

28
src/modules/punk-0.1.tm

@ -5262,6 +5262,8 @@ namespace eval punk {
set defaults [dict create\
-searchbase ""\
-tailglob "\uFFFF"\
-with_sizes "\uFFFF"\
-with_times "\uFFFF"\
]
lassign [dict values [get_leading_opts_and_values $defaults $args]] opts searchspecs
@ -5276,6 +5278,8 @@ namespace eval punk {
# -- --- --- --- --- --- ---
set opt_searchbase [dict get $opts -searchbase]
set opt_glob [dict get $opts -tailglob]
set opt_with_sizes [dict get $opts -with_sizes]
set opt_with_times [dict get $opts -with_times]
# -- --- --- --- --- --- ---
#we don't want to normalize..
@ -5333,10 +5337,22 @@ namespace eval punk {
}
}
if {$opt_with_sizes eq "\uFFFF"} {
#leave up to listing-provider defaults
set next_opt_with_sizes ""
} else {
set next_opt_with_sizes "-with_sizes $opt_with_sizes"
}
if {$opt_with_times eq "\uFFFF"} {
#leave up to listing-provider defaults
set next_opt_with_times ""
} else {
set next_opt_with_times "-with_times $opt_with_times"
}
if {$in_vfs} {
set listing [punk::du::lib::du_dirlisting_tclvfs $location -glob $glob -with_sizes f -with_times 1]
set listing [punk::du::lib::du_dirlisting_tclvfs $location -glob $glob {*}$next_opt_with_sizes {*}$next_opt_with_times]
} else {
set listing [punk::du::dirlisting $location -glob $glob -with_sizes f -with_times 1]
set listing [punk::du::dirlisting $location -glob $glob {*}$next_opt_with_sizes {*}$next_opt_with_times]
}
set dirs [dict get $listing dirs]
@ -5399,6 +5415,12 @@ namespace eval punk {
# -- ---
#can't lsort files without lsorting filesizes
#Note - the sort by index would convert an empty filesizes list to a list of empty strings - one for each entry in files
#We want to preserve the empty list if that's what the dirlisting mechanism returned (presumably because -with_sizes was 0 or explicitly excluded files)
if {[llength $filesizes] == 0} {
set sorted_files [lsort $files]
set sorted_filesizes [list]
} else {
set sortorder [lsort -indices $files]
set sorted_files [list]
set sorted_filesizes [list]
@ -5406,6 +5428,8 @@ namespace eval punk {
lappend sorted_files [lindex $files $i]
lappend sorted_filesizes [lindex $filesizes $i]
}
}
set files $sorted_files
set filesizes $sorted_filesizes
# -- ---

4
src/modules/punk/cap-999999.0a1.0.tm

@ -15,14 +15,16 @@
#*** !doctools
#[manpage_begin punk::cap 0 999999.0a1.0]
#[manpage_begin punkshell_module_punk::cap 0 999999.0a1.0]
#[copyright "2023 JMNoble - BSD licensed"]
#[titledesc {capability provider and handler plugin system}]
#[moddesc {punk capabilities plugin system}]
#[require punk::cap]
#[description]
#[keywords module capability plugin]
#[section Overview]
#[para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.
#[para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters
#[subsection Concepts]
#[para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API
#

153
src/modules/punk/du-999999.0a1.0.tm

@ -837,7 +837,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -921,48 +921,10 @@ namespace eval punk::du {
set dirs [struct::set difference [concat $hdirs $dirs[unset dirs]] [concat $links [list [file join $folderpath .] [file join $folderpath ..] ]]]
set links [lsort -unique [concat $links $hlinks]]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
#----
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
if {"windows" eq $::tcl_platform(platform)} {
@ -979,7 +941,7 @@ namespace eval punk::du {
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
proc du_dirlisting_tclvfs {folderpath args} {
@ -995,7 +957,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1048,55 +1010,14 @@ namespace eval punk::du {
#nested vfs mount.. REVIEW - does anything need special handling?
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
#we can halve the number of round trips on unix-like systems, where 'hidden' always corresponds to dotted files
@ -1107,7 +1028,7 @@ namespace eval punk::du {
-with_times 0\
]
set errors [dict create]
dict lappend errors $folderpath "metdata support incomplete - prefer du_dirlisting_generic"
dict lappend errors $folderpath "metadata support incomplete - prefer du_dirlisting_generic"
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob]
@ -1115,7 +1036,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1165,14 +1086,64 @@ namespace eval punk::du {
set files [struct::set difference $files[unset files] $links]
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes {} times {} flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
}
#return fsizes,allsizes,alltimes metadata in same order as files,dirs,links lists - if specified in sized_types
proc du_get_metadata_lists {sized_types timed_types files dirs links} {
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
#subst with na if empty?
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
#todo - fix . The list lengths will presumably match but have empty values if failed to stat
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
return [dict create fsizes $fsizes allsizes $allsizes alltimes $alltimes]
}
proc du_lit value {

4
src/modules/punk/mix/cli-0.3.tm

@ -867,6 +867,7 @@ namespace eval punk::mix::cli {
::kettle option set @srcscript $path
::kettle option set @srcdir [file dirname $path]
::kettle option set @goals $goals
#load standard recipes as listed in build.tcl
::source $path
puts stderr "recipes: [::kettle recipe names]"
::kettle recipe run {*}[::kettle option get @goals]
@ -884,6 +885,9 @@ namespace eval punk::mix::cli {
}
}
proc kettle_punk_recipes {} {
set txtdst ...
}
}
}

7
src/modules/punk/mix/commandset/doc-999999.0a1.0.tm

@ -173,9 +173,12 @@ namespace eval punk::mix::commandset::doc {
return $result
}
set original_wd [pwd]
cd $projectdir/src
set docroot $projectdir/src/doc
cd $docroot
dtplite validate $docroot
punk::mix::cli::lib::kettle_call lib validate-doc
#punk::mix::cli::lib::kettle_call lib validate-doc
cd $original_wd
}

2
src/modules/punk/mix/commandset/module-999999.0a1.0.tm

@ -273,7 +273,7 @@ namespace eval punk::mix::commandset::module {
set infile_version $build_version
}
set template_filedata [string map [list %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set template_filedata [string map [list %project% $projectname %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set modulefile $modulefolder/${moduletail}-$infile_version.tm
if {[file exists $modulefile]} {

61
src/modules/punk/mix/commandset/project-999999.0a1.0.tm

@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punk::mix::commandset::project 0 999999.0a1.0]
#[manpage_begin punkshell_module_punk::mix::commandset::project 0 999999.0a1.0]
#[copyright "2023"]
#[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}]
#[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}]
@ -44,7 +44,7 @@
#[para] Where the . in the above example is the prefix/command separator
#[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.
#[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname>
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects.<procname>
#[para]
#[subsection Concepts]
#[para] see punk::overlay
@ -498,11 +498,25 @@ namespace eval punk::mix::commandset::project {
#[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}]
namespace eval collection {
#*** !doctools
#[subsection {Namespace punk::mix::commandset::project::collection}]
#[para] commandset functions for operating with multiple projects.
#[para] It would usually be imported with the prefix "projects" and separator "." to result in commands such as: <ensemblecommand> projects.detail
#[list_begin definitions]
namespace export *
namespace path [namespace parent]
#e.g imported as 'projects'
proc _default {{glob {}} args} {
#*** !doctools
#[call [fun _default] [arg glob] [opt {option value...}]]
#[para]List projects under fossil management, showing fossil db location and number of checkouts
#[para]The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
#[para]glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s
#[para]The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.
#[para]e.g
#[para] punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection
#[para]Will result in the command being available as <ensemblecommand> projects
package require overtype
set db_projects [lib::get_projects $glob]
set col1items [lsearch -all -inline -index 0 -subindices $db_projects *]
@ -510,7 +524,7 @@ namespace eval punk::mix::commandset::project {
set checkouts [lsearch -all -inline -index 2 -subindices $db_projects *]
set col3items [lmap v $checkouts {llength $v}]
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1items] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -596,7 +610,7 @@ namespace eval punk::mix::commandset::project {
}
}
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1_dbfiles] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -656,15 +670,27 @@ namespace eval punk::mix::commandset::project {
proc work {{glob {}} args} {
package require sqlite3
set db_projects [lib::get_projects $glob]
if {[llength $db_projects] == 0} {
puts stderr "::punk::mix::commandset::project::work No Repo DB name matches found for '$glob'"
return ""
}
#list of lists of the form:
#{fosdb fname workdirlist}
set defaults [dict create\
-cd 0\
-detail "\uFFFF"\
]
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- ---
set opt_cd [dict get $opts -cd]
# -- --- --- --- --- --- ---
set opt_detail [dict get $opts -detail]
set opt_detail_explicit_zero 1 ;#default assumption only
if {$opt_detail eq "\uFFFF"} {
set opt_detail_explicit_zero 0
set opt_detail 0; #default
}
# -- --- --- --- --- --- ---
set workdir_dict [dict create]
set all_workdirs [list]
foreach pinfo $db_projects {
@ -732,10 +758,17 @@ namespace eval punk::mix::commandset::project {
set col_states [list]
set state_title ""
#if only one set of fossil checkouts in the resultset - retrieve workingdir state for each co
if {[llength [dict keys $fosdb_cache]] == 1} {
puts stderr "Result is a single project - gathering file state for each checkout folder"
#if only one set of fossil checkouts in the resultset and opt_detail is 0 and not explicit - retrieve workingdir state for each co
if {([llength [dict keys $fosdb_cache]] == 1)} {
if {!$opt_detail_explicit_zero} {
set opt_detail 1
}
puts stderr "Result is from a single repo db [dict keys $fosdb_cache]"
}
if {$opt_detail} {
puts stderr "Gathering file state for [llength $workdirs] checkout folder(s). Use -detail 0 to omit file state"
set c_rev [list]
set c_rev_iso [list]
set c_unchanged [list]
set c_changed [list]
set c_new [list]
@ -745,6 +778,7 @@ namespace eval punk::mix::commandset::project {
set wd_state [punk::repo::workingdir_state $wd]
set state_dict [punk::repo::workingdir_state_summary_dict $wd_state]
lappend c_rev [string range [dict get $state_dict revision] 0 9]
lappend c_rev_iso [dict get $state_dict revision_iso8601]
lappend c_unchanged [dict get $state_dict unchanged]
lappend c_changed [dict get $state_dict changed]
lappend c_new [dict get $state_dict new]
@ -756,6 +790,9 @@ namespace eval punk::mix::commandset::project {
set t0 "Revision"
set w0 [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev] {string length $v}]]
set c0 [string repeat " " $w0]
set t0b "Revision iso8601"
set w0b [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev_iso] {string length $v}]]
set c0b [string repeat " " $w0b]
set t1 "Unch"
set w1 [tcl::mathfunc::max {*}[lmap v [concat [list $t1] $c_unchanged] {string length $v}]]
set c1 [string repeat " " $w1]
@ -772,9 +809,9 @@ namespace eval punk::mix::commandset::project {
set w5 [tcl::mathfunc::max {*}[lmap v [concat [list $t5] $c_extra] {string length $v}]]
set c5 [string repeat " " $w5]
set state_title "[overtype::left $c0 $t0] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
set state_title "[overtype::left $c0 $t0] [overtype::left $c0b $t0b] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev iso $c_rev_iso u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::left $c0b $iso] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
}
}
@ -789,7 +826,7 @@ namespace eval punk::mix::commandset::project {
set title1 "Checkout dir"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $workdirs] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "Db name"
set title2 "Repo DB name"
set widest2 [tcl::mathfunc::max {*}[lmap v [concat [list $title2] $col_fnames] {string length $v}]]
set col2 [string repeat " " $widest2]
set title3 "CO dup"
@ -851,6 +888,8 @@ namespace eval punk::mix::commandset::project {
}
return $msg
}
#*** !doctools
#[list_end] [comment {-- end collection namespace definitions --}]
}
namespace eval lib {

73
src/modules/punk/mix/commandset/scriptwrap-999999.0a1.0.tm

@ -100,13 +100,18 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the tcl-payload or xxx-payload-pre-tcl site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} {
set defaults [list -askme 1 -template \uFFFF]
set opts [dict merge $defaults $args]
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
set defaults [dict create\
-askme 1\
-outputfolder "\uFFFF"\
-template "\uFFFF"\
]
set known_opts [dict keys $defaults]
dict for {k v} $args {
if {$k ni $known_opts} {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts"
}
}
set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -116,6 +121,17 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
}
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set opt_outputfolder [dict get $opts -outputfolder]
# -- --- --- --- --- --- --- --- --- --- --- ---
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
#first check if relative or absolute path matches a file
@ -124,7 +140,6 @@ namespace eval punk::mix::commandset::scriptwrap {
} else {
set specified_path [file join $startdir $filepath_or_scriptset]
}
set ext [string trim [file extension $filepath_or_scriptset] .]
set allowed_extensions [list wrapconfig tcl ps1 sh bash]
#set allowed_extensions [list tcl]
@ -203,7 +218,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
} else {
if {[file pathtype $something_found] ne "file"} {
if {[file type $something_found] ne "file"} {
puts stderr "Found '$something_found'"
puts stderr "wrap_in_multishell doesn't currently support a directory as the path."
puts stderr $usage
return false
@ -280,11 +296,37 @@ namespace eval punk::mix::commandset::scriptwrap {
}
#todo
#output_file extension depends on the template being used..
if {$opt_outputfolder eq "\uFFFF"} {
#outputfolder not explicitly specified by caller
if {[string length $projectroot]} {
set output_folder [file join $projectroot/bin]
} else {
set output_folder $startdir
}
} else {
if {[file pathtype $opt_outputfolder] eq "relative"} {
if {[string length $projectroot]} {
set output_folder [file join $projectroot $opt_outputfolder]
} else {
set output_folder [file join $startdir $opt_outputfolder]
}
} else {
set output_folder $opt_outputfolder
}
}
if {![file isdirectory $output_folder]} {
error "wrap_in_multishell: output folder '$output_folder' not found. Please ensure target directory exists"
}
set output_file $scriptset.cmd
#todo
#output_file extension may also depend on the template being used.. and/or the .wrapconfig
if {$::tcl_platform(platform) eq "windows"} {
set output_extension cmd
} else {
set output_extension sh
}
set output_file [file join $output_folder $scriptset.$output_extension]
if {[file exists $output_file]} {
error "wrap_in_multishell: target file $output_file already exists.. aborting"
}
@ -308,7 +350,7 @@ namespace eval punk::mix::commandset::scriptwrap {
set list_input_files [list]
if {$process_extensions eq "ALLFOUNDORCONFIGURED"} {
#todo - look for .wrapconfig or all extensions for the scriptset
puts stderr "Sorry - only single input file supported - implementation incomplete"
puts stderr "Sorry - only single input file supported. Supply a file extension or use a .wrapconfig with a single input file for now - implementation incomplete"
return false
} else {
lappend list_input_files $scriptroot/$scriptset.$ext
@ -332,8 +374,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stdout $ln
}
puts stdout "-----------------------------------------------\n"
if {$opt_askme} {
puts stdout "Target for above data is '$output_file'"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
@ -394,6 +436,11 @@ namespace eval punk::mix::commandset::scriptwrap {
puts -nonewline $fdtarget $newscript
close $fdtarget
puts stdout "Wrote script file at $output_file"
#even though chmod might exist on windows - we will leave permissions alone
if {$::tcl_platform(platform) ne "windows"} {
catch {exec chmod +x $output_file}
}
puts stdout "-done-"
return $output_file
}

6
src/modules/punk/mix/templates/layouts/project/.fossil-settings/ignore-glob

@ -1,4 +1,5 @@
.git
CVS
bin
lib
#The directory for compiled/built Tcl modules
@ -11,7 +12,10 @@ tmp
logs
_aside
#working directories
_build
src/docgen
#Built documentation
html
@ -28,6 +32,8 @@ tcl*.exe
#miscellaneous editor files etc
*.swp
.punkcheck
todo.txt
zig-cache

4
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/cap-0.1.0.tm

@ -15,14 +15,16 @@
#*** !doctools
#[manpage_begin punk::cap 0 0.1.0]
#[manpage_begin punkshell_module_punk::cap 0 0.1.0]
#[copyright "2023 JMNoble - BSD licensed"]
#[titledesc {capability provider and handler plugin system}]
#[moddesc {punk capabilities plugin system}]
#[require punk::cap]
#[description]
#[keywords module capability plugin]
#[section Overview]
#[para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability.
#[para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters
#[subsection Concepts]
#[para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API
#

71
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/docgen-0.1.0.tm

@ -0,0 +1,71 @@
# -*- tcl -*
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::docgen 0.1.0
# Meta platform tcl
# Meta license BSD
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
##e.g package require frobz
package require punk::repo
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::docgen {
proc get_doctools_comments {fname} {
#does no validation of doctools commands
#existence of string match #\**!doctools is taken as evidence enough that the file has inline doctools - review
if {![file exists $fname]} {
error "get_doctools_comments file '$fname' not found"
}
set fd [open $fname r]
set data [read $fd]
close $fd
if {![string match "*#\**!doctools*" $data]} {
return
}
set data [string map [list \r\n \n] $data]
set in_doctools 0
set doctools ""
foreach ln [split $data \n] {
set ln [string trim $ln]
if {$in_doctools && [string index $ln 0] != "#"} {
set in_doctools 0
} elseif {[string range $ln 0 1] == "#*"} {
#todo - process doctools ordering hints in tail of line
set in_doctools 1
} elseif {$in_doctools} {
append doctools [string range $ln 1 end] \n
}
}
return $doctools
}
#todo - proc autogen_doctools_comments {fname} {}
# - will probably need to use something like parsetcl - as we won't be able to reliably source in an interp without side-effects and use info body etc.
# - mechanism will be to autodocument namespaces, procs, methods where no #*** doctools indication present - but use existing doctools comments for that particular item if it is present.
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::docgen [namespace eval punk::docgen {
variable pkg punk::docgen
variable version
set version 0.1.0
}]
return

153
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/du-0.1.0.tm

@ -837,7 +837,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -921,48 +921,10 @@ namespace eval punk::du {
set dirs [struct::set difference [concat $hdirs $dirs[unset dirs]] [concat $links [list [file join $folderpath .] [file join $folderpath ..] ]]]
set links [lsort -unique [concat $links $hlinks]]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
#----
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
if {"windows" eq $::tcl_platform(platform)} {
@ -979,7 +941,7 @@ namespace eval punk::du {
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
proc du_dirlisting_tclvfs {folderpath args} {
@ -995,7 +957,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1048,55 +1010,14 @@ namespace eval punk::du {
#nested vfs mount.. REVIEW - does anything need special handling?
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $fsizes sizes $allsizes times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
#we can halve the number of round trips on unix-like systems, where 'hidden' always corresponds to dotted files
@ -1107,7 +1028,7 @@ namespace eval punk::du {
-with_times 0\
]
set errors [dict create]
dict lappend errors $folderpath "metdata support incomplete - prefer du_dirlisting_generic"
dict lappend errors $folderpath "metadata support incomplete - prefer du_dirlisting_generic"
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob]
@ -1115,7 +1036,7 @@ namespace eval punk::du {
set opt_with_sizes [dict get $opts -with_sizes]
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#dn't use string is boolean (false vs f problem)
#don't use string is boolean (false vs f problem where f indicates file)
if {$opt_with_sizes} {
set sized_types $ftypes
} else {
@ -1165,14 +1086,64 @@ namespace eval punk::du {
set files [struct::set difference $files[unset files] $links]
set vfsmounts [get_vfsmounts_in_folder $folderpath]
set mdata_lists [du_get_metadata_lists $sized_types $timed_types $files $dirs $links]
set effective_opts $opts
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes {} times {} flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $opts errors $errors]
}
#return fsizes,allsizes,alltimes metadata in same order as files,dirs,links lists - if specified in sized_types
proc du_get_metadata_lists {sized_types timed_types files dirs links} {
set meta_dict [dict create]
set meta_types [concat $sized_types $timed_types]
#known tcl stat keys 2023 - review
set empty_stat_dict [dict create atime {} ctime {} dev {} gid {} ino {} mode {} mtime {} nlink {} size {} type {} uid {}]
#make sure we call file stat only once per item
set statkeys [list]
if {[llength $meta_types]} {
foreach ft {f d l} lvar {files dirs links} {
if {"$ft" in $meta_types} {
foreach path [set $lvar] {
#caller may have read perm on the containing folder - but not on child item - so file stat could raise an error
if {![catch {file stat $path arrstat} errM]} {
dict set meta_dict $path [dict create shorttype $ft {*}[array get arrstat]]
} else {
dict lappend errors $path "file stat error: $errM"
dict set meta_dict $path [dict create shorttype $ft {*}$empty_stat_dict]
}
}
}
}
}
set fsizes [list]
set allsizes [dict create]
set alltimes [dict create]
#review birthtime field of stat? cross-platform differences ctime etc?
dict for {path pathinfo} $meta_dict {
set ft [dict get $pathinfo shorttype]
if {$ft in $sized_types} {
dict set allsizes $path [dict create bytes [dict get $pathinfo size]]
if {$ft eq "f"} {
#subst with na if empty?
lappend fsizes [dict get $pathinfo size]
}
}
if {$ft in $timed_types} {
dict set alltimes $path [dict create c [dict get $pathinfo ctime] a [dict get $pathinfo atime] m [dict get $pathinfo mtime]]
}
}
#todo - fix . The list lengths will presumably match but have empty values if failed to stat
if {"f" in $sized_types} {
if {[llength $fsizes] ne [llength $files]} {
dict lappend errors $folderpath "failed to retrieve all file sizes"
}
}
return [dict create fsizes $fsizes allsizes $allsizes alltimes $alltimes]
}
proc du_lit value {

4
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/cli-0.3.tm

@ -867,6 +867,7 @@ namespace eval punk::mix::cli {
::kettle option set @srcscript $path
::kettle option set @srcdir [file dirname $path]
::kettle option set @goals $goals
#load standard recipes as listed in build.tcl
::source $path
puts stderr "recipes: [::kettle recipe names]"
::kettle recipe run {*}[::kettle option get @goals]
@ -884,6 +885,9 @@ namespace eval punk::mix::cli {
}
}
proc kettle_punk_recipes {} {
set txtdst ...
}
}
}

7
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm

@ -173,9 +173,12 @@ namespace eval punk::mix::commandset::doc {
return $result
}
set original_wd [pwd]
cd $projectdir/src
set docroot $projectdir/src/doc
cd $docroot
dtplite validate $docroot
punk::mix::cli::lib::kettle_call lib validate-doc
#punk::mix::cli::lib::kettle_call lib validate-doc
cd $original_wd
}

2
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -273,7 +273,7 @@ namespace eval punk::mix::commandset::module {
set infile_version $build_version
}
set template_filedata [string map [list %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set template_filedata [string map [list %project% $projectname %pkg% $modulename %year% $year %license% $opt_license %version% $infile_version] $template_filedata]
set modulefile $modulefolder/${moduletail}-$infile_version.tm
if {[file exists $modulefile]} {

61
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm

@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punk::mix::commandset::project 0 0.1.0]
#[manpage_begin punkshell_module_punk::mix::commandset::project 0 0.1.0]
#[copyright "2023"]
#[titledesc {pmix commandset - project}] [comment {-- Name section and table of contents description --}]
#[moddesc {pmix CLI commandset - project}] [comment {-- Description at end of page heading --}]
@ -44,7 +44,7 @@
#[para] Where the . in the above example is the prefix/command separator
#[para]The prefix ('project' in the above example) can be any string desired to disambiguate commands imported from other commandsets.
#[para]The above results in the availability of the ensemble command: ::myproject::cli project.new, which is implemented in ::punk::mix::commandset::project::new
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as projects.<procname>
#[para]Similarly, procs under ::punk::mix::commandset::project::collection will be available as subcommands of the ensemble as <ensemblecommand> projects.<procname>
#[para]
#[subsection Concepts]
#[para] see punk::overlay
@ -498,11 +498,25 @@ namespace eval punk::mix::commandset::project {
#[list_end] [comment {--- end definitions namespace punk::mix::commandset::project ---}]
namespace eval collection {
#*** !doctools
#[subsection {Namespace punk::mix::commandset::project::collection}]
#[para] commandset functions for operating with multiple projects.
#[para] It would usually be imported with the prefix "projects" and separator "." to result in commands such as: <ensemblecommand> projects.detail
#[list_begin definitions]
namespace export *
namespace path [namespace parent]
#e.g imported as 'projects'
proc _default {{glob {}} args} {
#*** !doctools
#[call [fun _default] [arg glob] [opt {option value...}]]
#[para]List projects under fossil management, showing fossil db location and number of checkouts
#[para]The glob argument is optional unless option/value pairs are also supplied, in which case * should be explicitly supplied
#[para]glob restricts output based on the name of the fossil db file e.g s* for all projects beginning with s
#[para]The _default function is made available in the ensemble by the name of the prefix used when importing the commandset.
#[para]e.g
#[para] punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection
#[para]Will result in the command being available as <ensemblecommand> projects
package require overtype
set db_projects [lib::get_projects $glob]
set col1items [lsearch -all -inline -index 0 -subindices $db_projects *]
@ -510,7 +524,7 @@ namespace eval punk::mix::commandset::project {
set checkouts [lsearch -all -inline -index 2 -subindices $db_projects *]
set col3items [lmap v $checkouts {llength $v}]
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1items] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -596,7 +610,7 @@ namespace eval punk::mix::commandset::project {
}
}
set title1 "Fossil DB"
set title1 "Fossil Repo DB"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $col1_dbfiles] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "File Name"
@ -656,15 +670,27 @@ namespace eval punk::mix::commandset::project {
proc work {{glob {}} args} {
package require sqlite3
set db_projects [lib::get_projects $glob]
if {[llength $db_projects] == 0} {
puts stderr "::punk::mix::commandset::project::work No Repo DB name matches found for '$glob'"
return ""
}
#list of lists of the form:
#{fosdb fname workdirlist}
set defaults [dict create\
-cd 0\
-detail "\uFFFF"\
]
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- ---
set opt_cd [dict get $opts -cd]
# -- --- --- --- --- --- ---
set opt_detail [dict get $opts -detail]
set opt_detail_explicit_zero 1 ;#default assumption only
if {$opt_detail eq "\uFFFF"} {
set opt_detail_explicit_zero 0
set opt_detail 0; #default
}
# -- --- --- --- --- --- ---
set workdir_dict [dict create]
set all_workdirs [list]
foreach pinfo $db_projects {
@ -732,10 +758,17 @@ namespace eval punk::mix::commandset::project {
set col_states [list]
set state_title ""
#if only one set of fossil checkouts in the resultset - retrieve workingdir state for each co
if {[llength [dict keys $fosdb_cache]] == 1} {
puts stderr "Result is a single project - gathering file state for each checkout folder"
#if only one set of fossil checkouts in the resultset and opt_detail is 0 and not explicit - retrieve workingdir state for each co
if {([llength [dict keys $fosdb_cache]] == 1)} {
if {!$opt_detail_explicit_zero} {
set opt_detail 1
}
puts stderr "Result is from a single repo db [dict keys $fosdb_cache]"
}
if {$opt_detail} {
puts stderr "Gathering file state for [llength $workdirs] checkout folder(s). Use -detail 0 to omit file state"
set c_rev [list]
set c_rev_iso [list]
set c_unchanged [list]
set c_changed [list]
set c_new [list]
@ -745,6 +778,7 @@ namespace eval punk::mix::commandset::project {
set wd_state [punk::repo::workingdir_state $wd]
set state_dict [punk::repo::workingdir_state_summary_dict $wd_state]
lappend c_rev [string range [dict get $state_dict revision] 0 9]
lappend c_rev_iso [dict get $state_dict revision_iso8601]
lappend c_unchanged [dict get $state_dict unchanged]
lappend c_changed [dict get $state_dict changed]
lappend c_new [dict get $state_dict new]
@ -756,6 +790,9 @@ namespace eval punk::mix::commandset::project {
set t0 "Revision"
set w0 [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev] {string length $v}]]
set c0 [string repeat " " $w0]
set t0b "Revision iso8601"
set w0b [tcl::mathfunc::max {*}[lmap v [concat [list $t0] $c_rev_iso] {string length $v}]]
set c0b [string repeat " " $w0b]
set t1 "Unch"
set w1 [tcl::mathfunc::max {*}[lmap v [concat [list $t1] $c_unchanged] {string length $v}]]
set c1 [string repeat " " $w1]
@ -772,9 +809,9 @@ namespace eval punk::mix::commandset::project {
set w5 [tcl::mathfunc::max {*}[lmap v [concat [list $t5] $c_extra] {string length $v}]]
set c5 [string repeat " " $w5]
set state_title "[overtype::left $c0 $t0] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
set state_title "[overtype::left $c0 $t0] [overtype::left $c0b $t0b] [overtype::right $c1 $t1] [overtype::right $c2 $t2] [overtype::right $c3 $t3] [overtype::right $c4 $t4] [overtype::right $c5 $t5]"
foreach r $c_rev iso $c_rev_iso u $c_unchanged c $c_changed n $c_new m $c_missing e $c_extra {
lappend col_states "[overtype::left $c0 $r] [overtype::left $c0b $iso] [overtype::right $c1 $u] [overtype::right $c2 $c] [overtype::right $c3 $n] [overtype::right $c4 $m] [overtype::right $c5 $e]"
}
}
@ -789,7 +826,7 @@ namespace eval punk::mix::commandset::project {
set title1 "Checkout dir"
set widest1 [tcl::mathfunc::max {*}[lmap v [concat [list $title1] $workdirs] {punk::strlen $v}]]
set col1 [string repeat " " $widest1]
set title2 "Db name"
set title2 "Repo DB name"
set widest2 [tcl::mathfunc::max {*}[lmap v [concat [list $title2] $col_fnames] {string length $v}]]
set col2 [string repeat " " $widest2]
set title3 "CO dup"
@ -851,6 +888,8 @@ namespace eval punk::mix::commandset::project {
}
return $msg
}
#*** !doctools
#[list_end] [comment {-- end collection namespace definitions --}]
}
namespace eval lib {

73
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm

@ -100,13 +100,18 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the tcl-payload or xxx-payload-pre-tcl site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} {
set defaults [list -askme 1 -template \uFFFF]
set opts [dict merge $defaults $args]
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
set defaults [dict create\
-askme 1\
-outputfolder "\uFFFF"\
-template "\uFFFF"\
]
set known_opts [dict keys $defaults]
dict for {k v} $args {
if {$k ni $known_opts} {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts"
}
}
set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -116,6 +121,17 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
}
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template]
set opt_outputfolder [dict get $opts -outputfolder]
# -- --- --- --- --- --- --- --- --- --- --- ---
set ext [file extension $filepath_or_scriptset]
set startdir [pwd]
#first check if relative or absolute path matches a file
@ -124,7 +140,6 @@ namespace eval punk::mix::commandset::scriptwrap {
} else {
set specified_path [file join $startdir $filepath_or_scriptset]
}
set ext [string trim [file extension $filepath_or_scriptset] .]
set allowed_extensions [list wrapconfig tcl ps1 sh bash]
#set allowed_extensions [list tcl]
@ -203,7 +218,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage
return false
} else {
if {[file pathtype $something_found] ne "file"} {
if {[file type $something_found] ne "file"} {
puts stderr "Found '$something_found'"
puts stderr "wrap_in_multishell doesn't currently support a directory as the path."
puts stderr $usage
return false
@ -280,11 +296,37 @@ namespace eval punk::mix::commandset::scriptwrap {
}
#todo
#output_file extension depends on the template being used..
if {$opt_outputfolder eq "\uFFFF"} {
#outputfolder not explicitly specified by caller
if {[string length $projectroot]} {
set output_folder [file join $projectroot/bin]
} else {
set output_folder $startdir
}
} else {
if {[file pathtype $opt_outputfolder] eq "relative"} {
if {[string length $projectroot]} {
set output_folder [file join $projectroot $opt_outputfolder]
} else {
set output_folder [file join $startdir $opt_outputfolder]
}
} else {
set output_folder $opt_outputfolder
}
}
if {![file isdirectory $output_folder]} {
error "wrap_in_multishell: output folder '$output_folder' not found. Please ensure target directory exists"
}
set output_file $scriptset.cmd
#todo
#output_file extension may also depend on the template being used.. and/or the .wrapconfig
if {$::tcl_platform(platform) eq "windows"} {
set output_extension cmd
} else {
set output_extension sh
}
set output_file [file join $output_folder $scriptset.$output_extension]
if {[file exists $output_file]} {
error "wrap_in_multishell: target file $output_file already exists.. aborting"
}
@ -308,7 +350,7 @@ namespace eval punk::mix::commandset::scriptwrap {
set list_input_files [list]
if {$process_extensions eq "ALLFOUNDORCONFIGURED"} {
#todo - look for .wrapconfig or all extensions for the scriptset
puts stderr "Sorry - only single input file supported - implementation incomplete"
puts stderr "Sorry - only single input file supported. Supply a file extension or use a .wrapconfig with a single input file for now - implementation incomplete"
return false
} else {
lappend list_input_files $scriptroot/$scriptset.$ext
@ -332,8 +374,8 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stdout $ln
}
puts stdout "-----------------------------------------------\n"
if {$opt_askme} {
puts stdout "Target for above data is '$output_file'"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
@ -394,6 +436,11 @@ namespace eval punk::mix::commandset::scriptwrap {
puts -nonewline $fdtarget $newscript
close $fdtarget
puts stdout "Wrote script file at $output_file"
#even though chmod might exist on windows - we will leave permissions alone
if {$::tcl_platform(platform) ne "windows"} {
catch {exec chmod +x $output_file}
}
puts stdout "-done-"
return $output_file
}

4
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/ns-0.1.0.tm

@ -1547,6 +1547,7 @@ namespace eval punk::ns {
foreach fullv $varnames {
set v [namespace tail $fullv]
upvar 1 $v var
if {[info exists var]} {
if {$v eq "args"} {
dict set capturevars "prev_args$n" [list var $var]
} else {
@ -1556,6 +1557,9 @@ namespace eval punk::ns {
dict set capturearrs $v [array get var]
}
}
} else {
#A variable can show in the results for 'info vars' (or nsvars) but still not exist. e.g a 'variable x' declaration in the namespace where the variable has never been set
}
}
return [dict create vars $capturevars arrs $capturearrs]
} } [info vars [namespace current]::*] ;#we are relying on info vars ::::* returning same as info vars ::* - a bit hacky (don't want to set any extra vars in the ns)

397
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/path-0.1.0.tm

@ -0,0 +1,397 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# 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) 2023
#
# @@ Meta Begin
# Application punk::path 0.1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.1.0]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
#[require punk::path]
#[description]
#[keywords module path filesystem]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::path
#[para] Filesystem path utility functions
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::path
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::class {
#*** !doctools
#[subsection {Namespace punk::path::class}]
#[para] class definitions
if {[info commands [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 ---}]
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path {
namespace export *
#variable xyz
#*** !doctools
#[subsection {Namespace punk::path}]
#[para] Core API functions for punk::path
#[list_begin definitions]
proc pathglob_as_re {pathglob} {
#*** !doctools
#[call [fun pathglob_as_re] [arg pathglob]]
#[para] Returns a regular expression for matching a path to a glob pattern which can contain glob chars *|? in any segment of the path structure
#[para] ** matches any number of subdirectories.
#[para] e.g /etc/**/*.txt will match any .txt files at any depth below /etc (except directly within /etc itself)
#[para] e.g /etc/**.txt will match any .txt files at any depth below /etc
#[para] any segment that does not contain ** must match exactly one segment in the path
#[para] e.g the glob /etc/*/*.doc - will match any .doc files that are exactly one tree level below /etc
#[para] The pathglob doesn't have to contain glob characters, in which case the returned regex will match the pathglob exactly as specified.
#[para] Regular expression syntax is deliberateley not supported within the pathglob string so that supplied regex characters will be treated as literals
#todo - consider whether a way to escape the glob chars ? * is practical - to allow literals ? *
# - would require counting immediately-preceding backslashes
set pats [list]
foreach seg [file split $pathglob] {
if {[string range $seg end end] eq "/"} {
set seg [string range $seg 0 end-1] ;# e.g c:/ -> c: / -> "" so that join at end doesn't double up
}
if {$seg eq "*"} {
lappend pats {[^/]*}
} elseif {$seg eq "**"} {
lappend pats {.*}
} else {
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals
set seg [string map [list . {[.]}] $seg]
if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg]
lappend pats "$pat"
} else {
lappend pats "$seg"
}
}
}
return "^[join $pats /]\$"
}
proc globmatchpath {pathglob path args} {
#*** !doctools
#[call [fun globmatchpath] [arg pathglob] [arg path] [opt {option value...}]]
#[para] Return true if the pathglob matches the path
#[para] see [fun pathglob_as_re] for pathglob description
#[para] Caller must ensure that file separator is forward slash. (e.g use file normalize on windows)
#[para]
#[para] Known options:
#[para] -nocase 0|1 (default 0 - case sensitive)
#[para] If -nocase is not supplied - default to case sensitive *except for driveletter*
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.
set defaults [dict create\
-nocase \uFFFF\
]
set known_opts [dict keys $defaults]
set opts [dict merge $defaults $args]
dict for {k v} $args {
if {$k ni $known_opts} {
error "Unrecognised options $k - known options: $known_opts"
}
}
# -- --- --- --- --- ---
set opt_nocase [dict get $opts -nocase]
set explicit_nocase 1 ;#default to disprove
if {$opt_nocase eq "\uFFFF"} {
set opt_nocase 0
set explicit_nocase 0
}
# -- --- --- --- --- ---
if {$opt_nocase} {
return [regexp -nocase [pathglob_as_re $pathglob] $path]
} else {
set re [pathglob_as_re $pathglob]
if {$explicit_nocase} {
set ismatch [regexp $re $path] ;#explicit -nocase 0 - require exact match of path literals including driveletter
} else {
#caller is using default for -nocase - which indicates case sensitivity - but we have an exception for the driveletter.
set re_segments [file split $re] ;#Note that file split c:/etc gives {c:/ etc} but file split ^c:/etc gives {^c: etc}
set first_seg [lindex $re_segments 0]
if {[regexp {^\^(.{1}):$} $first_seg _match driveletter]} {
#first part of re is like "^c:" i.e a drive letter
set chars [string tolower $driveletter][string toupper $driveletter]
set re [join [concat "^\[$chars\]:" [lrange $re_segments 1 end]] /] ;#rebuild re with case insensitive driveletter only - use join - not file join. file join will misinterpret leading re segment.
}
#puts stderr "-->re: $re"
set ismatch [regexp $re $path]
}
}
return $ismatch
}
#todo - implement treefiles which acts like dirfiles but allows path globbing in the same way as punk::ns::ns/
#then review if treefiles can replace dirfiles or if both should exist (dirfiles can have literal glob chars in path segments - but that is a rare usecase)
proc treefilenames {basepath tailglob args} {
#*** !doctools
#[call [fun treefilenames] [arg basepath] [arg tailglob] [opt {option value...}]]
#basic (glob based) list of filenames matching tailglob - recursive
#no natsorting - so order is dependent on filesystem
set defaults [dict create\
-call-depth-internal 0\
-antiglob_paths {}\
]
set opts [dict merge $defaults $args]
set opt_antiglob_paths [dict get $opts -antiglob_paths]
set CALLDEPTH [dict get $opts -call-depth-internal]
set files [list]
if {$CALLDEPTH == 0} {
if {![file isdirectory $basepath]} {
return [list]
}
}
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $basepath]} {
set skip 1
break
}
}
if {$skip} {
return [list]
}
#todo - account for vfs where matched path could appear to be a directory but is mounted so could be a desired match?
set dirfiles [glob -nocomplain -dir $basepath -type f $tailglob]
lappend files {*}$dirfiles
set dirdirs [glob -nocomplain -dir $basepath -type d *]
foreach dir $dirdirs {
set skip 0
foreach anti $opt_antiglob_paths {
if {[globmatchpath $anti $dir]} {
set skip 1
break
}
}
if {$skip} {
continue
}
set nextargs [dict merge $args [list -call-depth-internal [incr CALLDEPTH]]]
lappend files {*}[treefilenames $dir $tailglob {*}$nextargs]
}
return $files
}
#maint warning - also in punkcheck
proc relative {reference location} {
#*** !doctools
#[call [fun relative] [arg reference] [arg location]]
#[para] Taking two directory paths, a reference and a location, computes the path
# of the location relative to the reference.
#[list_begin itemized]
#[item]
#[para] Arguments:
# [list_begin arguments]
# [arg_def string reference] The path from which the relative path to location is determined.
# [arg_def string location] The location path which may be above or below the reference path
# [list_end]
#[item]
#[para] Results:
#[para] The relative path of the location to the reference path.
#[para] Will return a single dot "." if the paths are the same
#[item]
#[para] Notes:
#[para] Both paths must be the same type - ie both absolute or both relative
#[para] Case sensitive. ie relative /etc /etC
# will return ../etC
#[para] On windows, the drive-letter component (only) is not case sensitive
#[para] ie relative c:/etc C:/etc returns .
#[para] but relative c:/etc C:/Etc returns ../Etc
#[para] On windows, if the paths are absolute and specifiy different volumes, only the location will be returned.
# ie relative c:/etc d:/etc/blah
# returns d:/etc/blah
#[list_end]
#see also kettle
# Modified copy of ::fileutil::relative (tcllib)
# Adapted to 8.5 ({*}).
#review - check volume info on windows.. UNC paths?
if {[file pathtype $reference] ne [file pathtype $location]} {
return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $reference] vs. [file pathtype $location], ($reference vs. $location)"
}
#avoid normalizing if possible (file normalize *very* expensive on windows)
set do_normalize 0
if {[file pathtype $reference] eq "relative"} {
#if reference is relative so is location
if {[regexp {[.]{2}} [list $reference $location]]} {
set do_normalize 1
}
if {[regexp {[.]/} [list $reference $location]]} {
set do_normalize 1
}
} else {
set do_normalize 1
}
if {$do_normalize} {
set reference [file normalize $reference]
set location [file normalize $location]
}
set save $location
set reference [file split $reference]
set location [file split $location]
while {[lindex $location 0] eq [lindex $reference 0]} {
set location [lrange $location 1 end]
set reference [lrange $reference 1 end]
if {![llength $location]} {break}
}
set location_len [llength $location]
set reference_len [llength $reference]
if {($location_len == 0) && ($reference_len == 0)} {
# Cases:
# (a) reference == location
set location .
} else {
# Cases:
# (b) ref is: ref/sub = sub
# loc is: ref = {}
# (c) ref is: ref = {}
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
incr reference_len -1
}
set location [file join {*}$location]
}
return $location
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::path::lib {
namespace export *
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::path::lib}]
#[para] Secondary functions that are part of the API
#[list_begin definitions]
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::path::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::path::system {
#*** !doctools
#[subsection {Namespace punk::path::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.1.0
}]
return
#*** !doctools
#[manpage_end]

40
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punk/repo-0.1.1.tm

@ -314,6 +314,10 @@ namespace eval punk::repo {
# -repotypes is an ordered list - if the closest repo is multi-typed the order will determine which is used.
# This deliberately doesn't allow bypassing a sub-repo to look for a higher-level repo in a repo-nest.
# The theory is that sub-repos shouldn't have their contents directly tracked directly by higher-level repos anyway
#REVIEW - if closest repo is both fossil and git - we only return info for one, with fossil being preferenced
#This may not make sense if we want to allow fossil tracking of projects where git is the primary repotype and fossil is just used to enable us to enumerate projects?
#does a dual git/fossil repo make sense if both are committing??
# see: https://fossil-scm.org/home/doc/trunk/www/inout.wiki for bidirectional sync info
proc workingdir_state {{abspath {}} args} {
set defaults [list\
-repotypes [list fossil git]\
@ -364,6 +368,9 @@ namespace eval punk::repo {
}
set resultdict [dict create repodir $repodir subpath $subpath]
#set defaults in case no supported repotype found
set revision ""
set revision_iso8601 ""
set pathdict [dict create]
if {![llength $repotypes_to_query]} {
@ -384,9 +391,15 @@ namespace eval punk::repo {
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$fossil_cmd status --all --differ --merge $abspath]} fossilstate]} {
error "workingdir_state error: Unable to retrieve workingdir state using fossil. Errormsg: $fossilstate"
}
# line: checkout: fb971...
set revision [lindex [grep {checkout:*} $fossilstate] 0 1]
# line: checkout: fb971... Y-m-d H:M:S TZ
set checkout_info [lindex [grep {checkout:*} $fossilstate] 0] ;#grep returns a list - but it should always be a single match in this case
set revision [lindex $checkout_info 0 1]
#set checkrevision [fossil_revision $abspath]
lassign $checkout_info _key revision revision_ymd revision_hms revision_tz
if {$revision_tz eq "UTC"} {
set revision_tz "+0000" ;#normalize UTC for consistency with git tz output - review - should do date-math if necessary on git and fossil to bring all to +0000 (is fossil always UTC? git )
}
set revision_iso8601 "${revision_ymd}T${revision_hms}${revision_tz}"
dict set resultdict ahead ""
@ -442,6 +455,25 @@ namespace eval punk::repo {
puts stderr "workingdir_state: git revision is (initial) - no file state to gather"
break
}
# -- --- --- --- ---
#could use %ci for ISO8601 data - see git-show manpage, but this will be in timezone of developer's machine - we need it in UTC for comparison to fossil outputs and other devs
set had_TZ 0
if {[info exists ::env(TZ)]} {
set TZ_prev $::env(TZ)
set had_TZ 1
}
set ::env(TZ) "UTC0"
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$git_cmd show -s --date=format-local:%Y:%m:%dT%H:%M:%S+0000 --format=format:%cd -- $abspath]} revision_iso8601]} {
puts stderr "workingdir_state warning: Unable to retrieve workingdir state using git. Errormsg: $gitstate"
}
if {$had_TZ} {
set ::env(TZ) $TZ_prev
} else {
unset ::env(TZ)
}
# -- --- --- --- ---
dict set resultdict ahead ""
dict set resultdict behind ""
set aheadbehind [lindex [grep {# branch.ab *} $gitstate] 0]
@ -525,6 +557,7 @@ namespace eval punk::repo {
}
}
dict set resultdict revision $revision
dict set resultdict revision_iso8601 $revision_iso8601
dict set resultdict paths $pathdict
return $resultdict
}
@ -547,6 +580,7 @@ namespace eval punk::repo {
repodir repodir\
subpath subpath\
revision revision\
revision_iso8601 revision_iso8601\
ahead ahead\
behind behind\
repotype repotype\
@ -590,7 +624,7 @@ namespace eval punk::repo {
}
set filestates [dict values [dict get $repostate paths]]
set path_count_fields [list unchanged changed new missing extra]
set state_fields [list ahead behind repodir subpath repotype revision]
set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601]
set dresult [dict create]
foreach f $state_fields {
dict set dresult $f [dict get $repostate $f]

2
src/modules/punk/mix/templates/layouts/project/src/bootsupport/modules/punkcheck-0.1.0.tm

@ -743,7 +743,7 @@ namespace eval punkcheck {
#The files we depended on for the previous record haven't changed themselves - but the list of files has (reduced by one)
proc installfile_add_source_and_fetch_metadata {punkcheck_folder source_relpath file_record} {
if {![lib::is_file_record_inprogress $file_record]} {
error "installfile_add_source_and_fetch_metdata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
error "installfile_add_source_and_fetch_metadata error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
}
set ts_start [clock microseconds]
set last_installrecord [lib::file_record_get_last_installrecord $file_record]

2
src/modules/punk/mix/templates/layouts/project/src/doc/project_changes.man

@ -1,5 +1,5 @@
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin project_changes n 8]
[manpage_begin %project%__project_changes n 8]
[include include/general.inc]
[titledesc {%project% Changes}]
[description]

2
src/modules/punk/mix/templates/layouts/project/src/doc/project_intro.man

@ -1,5 +1,5 @@
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin project_intro n 8]
[manpage_begin %project%__project_intro n 8]
[include include/general.inc]
[titledesc {Introduction to %project%}]
[description]

49
src/modules/punk/mix/templates/modules/template_cli-0.0.1.tm

@ -12,12 +12,57 @@
# Meta license %license%
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin %project%_cli-module_%pkg% 0 999999.0a1.0]
#[copyright "%year%"]
#[titledesc {Command Line Interface Module}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require %pkg%]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of %pkg%
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by %pkg%
#[list_begin itemized]
package require Tcl 8.6
package require punk::overlay
package require punk::mix::base
package require punk::mix::util
#*** !doctools
#[item] [package {Tcl 8.6}]
#[item] [package {punk::overlay}]
#[item] [package {punk::mix::base}]
#[item] [package {punk::mix::util}]
# #package require frobz
# #*** !doctools
# #[item] [package {frobz}]
#*** !doctools
#[list_end]
namespace eval %pkg% {
namespace ensemble create
#package require punk::overlay
#punk::overlay::import_commandset debug. ::punk:mix::commandset::debug
#punk::overlay::import_commandset debug . ::punk:mix::commandset::debug
proc help {args} {
@ -46,8 +91,6 @@ namespace eval %pkg% {
::punk::mix::base::_cli {*}$args
}
variable default_command help
package require punk::mix::base
package require punk::overlay
punk::overlay::custom_from_base [namespace current] ::punk::mix::base
}

3
src/modules/punk/mix/templates/modules/template_module-0.0.1.tm

@ -17,12 +17,13 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin %pkg% 0 999999.0a1.0]
#[manpage_begin %project%_module_%pkg% 0 999999.0a1.0]
#[copyright "%year%"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require %pkg%]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++

270
src/modules/punk/mix/templates/utility/scriptappwrappers/punk-multishell-old.cmd

@ -0,0 +1,270 @@
set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershell;proc Hide s {proc $s args {}}; Hide :;rename set s2;Hide set;s2 1 list]"; set -- : "$@"; $1 = @'
: heredoc1 - hide from powershell (close sqote for unix shells) ' \
: << 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
: .bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl \
: "[Hide @ECHO; Hide ); Hide (;Hide echo]#not necessary but can help avoid errs in testing"
: Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
@REM {
@REM DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required and will reduce functionality.
@REM Even comment lines can be part of the functionality of this script - modify with care.
@REM Change the value of nextshell in the next line if desired, and code within payload sections as appropriate.
@SET "nextshell=pwsh"
@REM nextshell set to pwsh,sh,bash or tclsh
@REM @ECHO nextshell is %nextshell%
@SET "validshells=pwsh,sh,bash,tclsh"
@CALL SET keyRemoved=%%validshells:%nextshell%=%%
@REM Note that 'powershell' e.g v5 is just a fallback for when pwsh is not available
@REM ## ### ### ### ### ### ### ### ### ### ### ### ### ###
@REM -- cmd/batch file section (ignored on unix)
@REM -- This section intended only to launch the next shell
@REM -- Avoid customising this if possible. cmd/batch script is probably the least expressive language.
@REM -- custom windows payloads should be in powershell,tclsh or sh/bash code sections
@REM ## ### ### ### ### ### ### ### ### ### ### ### ### ###
@SETLOCAL EnableExtensions EnableDelayedExpansion
@SET "winpath=%~dp0"
@SET "fname=%~nx0"
@REM @ECHO fname %fname%
@REM @ECHO winpath %winpath%
@IF %nextshell%==pwsh (
CALL pwsh -nop -c set-executionpolicy -Scope CurrentUser RemoteSigned
COPY "%~dp0%~n0.cmd" "%~dp0%~n0.ps1" >NUL
REM test availability of preferred option of powershell7+ pwsh
CALL pwsh -nop -nol -c write-host "statusmessage: pwsh-found" >NUL
SET pwshtest_exitcode=!errorlevel!
REM ECHO pwshtest_exitcode !pwshtest_exitcode!
IF !pwshtest_exitcode!==0 CALL pwsh -nop -nol "%~dp0%~n0.ps1" %* & SET task_exitcode=!errorlevel!
REM fallback to powershell if pwsh failed
IF NOT !pwshtest_exitcode!==0 (
REM CALL powershell -nop -nol -c write-host powershell-found
CALL powershell -nop -nol -file "%~dp0%~n0.ps1" %*
SET task_exitcode=!errorlevel!
)
) ELSE (
IF %nextshell%==bash (
CALL :getWslPath %winpath% wslpath
REM ECHO wslfullpath "!wslpath!%fname%"
CALL %nextshell% "!wslpath!%fname%" %* & SET task_exitcode=!errorlevel!
) ELSE (
REM probably tclsh or sh
IF NOT "x%keyRemoved%"=="x%validshells%" (
REM sh uses /c/ instead of /mnt/c - at least if using msys. Todo, review what is the norm on windows with and without msys2,cygwin,wsl
REM and what logic if any may be needed. For now sh with /c/xxx seems to work the same as sh with c:/xxx
CALL %nextshell% "%~dp0%fname%" %* & SET task_exitcode=!errorlevel!
) ELSE (
ECHO %fname% has invalid nextshell value %nextshell% valid options are %validshells%
SET task_exitcode=66
GOTO :exit
)
)
)
@GOTO :endlib
:getWslPath
@SETLOCAL
@SET "_path=%~p1"
@SET "name=%~nx1"
@SET "drive=%~d1"
@SET "rtrn=%~2"
@SET "result=/mnt/%drive:~0,1%%_path:\=/%%name%"
@ENDLOCAL & (
@if "%~2" neq "" (
SET "%rtrn%=%result%"
) ELSE (
ECHO %result%
)
)
@GOTO :eof
:endlib
: \
@REM @SET taskexit_code=!errorlevel! & goto :exit
@GOTO :exit
# }
# rem call %nextshell% "%~dp0%~n0.cmd" %*
# -*- tcl -*-
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- tcl script section
# -- This is a punk multishell file
# -- Primary payload target is Tcl, with sh,bash,powershell as helpers
# -- but it may equally be used with any of these being the primary script.
# -- It is tuned to run when called as a batch file, a tcl script a sh/bash script or a pwsh/powershell script
# -- i.e it is a polyglot file.
# -- The specific layout including some lines that appear just as comments is quite sensitive to change.
# -- It can be called on unix or windows platforms with or without the interpreter being specified on the commandline.
# -- e.g ./filename.polypunk.cmd in sh or bash
# -- e.g tclsh filename.cmd
# --
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
rename set ""; rename s2 set; set k {-- "$@" "a}; if {[info exists ::env($k)]} {unset ::env($k)} ;# tidyup
Hide :exit;Hide {<#};Hide '@
namespace eval ::punk::multishell {
set last_script_root [file dirname [file normalize ${argv0}/__]]
set last_script [file dirname [file normalize [info script]/__]]
if {[info exists argv0] &&
$last_script eq $last_script_root
} {
set ::punk::multishell::is_main($last_script) 1 ;#run as executable/script - likely desirable to launch application and return an exitcode
} else {
set ::punk::multishell::is_main($last_script) 0 ;#sourced - likely to be being used as a library - no launch, no exit. Can use return.
}
if {"::punk::multishell::is_main" ni [info commands ::punk::multishell::is_main]} {
proc ::punk::multishell::is_main {{script_name {}}} {
if {$script_name eq ""} {
set script_name [file dirname [file normalize [info script]/--]]
}
if {![info exists ::punk::multishell::is_main($script_name)]} {
#e.g a .dll or something else unanticipated
puts stderr "Warning punk::multishell didn't recognize info script result: $script_name - will treat as if sourced and return instead of exiting"
puts stderr "Info: script_root: [file dirname [file normalize ${argv0}/__]]"
return 0
}
return [set ::punk::multishell::is_main($script_name)]
}
}
}
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin Tcl Payload
#puts "script : [info script]"
#puts "argcount : $::argc"
#puts "argvalues: $::argv"
#puts "argv0 : $::argv0"
# -- --- --- --- --- --- --- --- --- --- --- ---
#<tcl-payload>
#</tcl-payload>
# -- --- --- --- --- --- --- --- --- --- --- ---
# -- Best practice is to always return or exit above, or just by leaving the below defaults in place.
# -- If the multishell script is modified to have Tcl below the Tcl Payload section,
# -- then Tcl bracket balancing needs to be carefully managed in the shell and powershell sections below.
# -- Only the # in front of the two relevant if statements below needs to be removed to enable Tcl below
# -- but the sh/bash 'then' and 'fi' would also need to be uncommented.
# -- This facility left in place for experiments on whether configuration payloads etc can be appended
# -- to tail of file - possibly binary with ctrl-z char - but utility is dependent on which other interpreters/shells
# -- can be made to ignore/cope with such data.
if {[::punk::multishell::is_main]} {
exit 0
} else {
return
}
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end Tcl Payload
# end hide from unix shells \
HEREDOC1B_HIDE_FROM_BASH_AND_SH
# sh/bash \
shift && set -- "${@:1:$#-1}"
#------------------------------------------------------
# -- This if block only needed if Tcl didn't exit or return above.
if false==false # else {
then
:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- sh/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 @call line above ... to something like @call sh ... @call bash .. or @call env sh ... etc as appropriate
# -- if sh/bash scripting needs to run on windows too.
# --
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin sh Payload
#printf "start of bash or sh code"
#<shell-payload-pre-tcl>
#</shell-payload-pre-tcl>
# -- --- --- --- --- --- --- ---
#<shell-launch-tcl>
exitcode=0 ;#default assumption
#-- sh/bash launches Tcl here instead of shebang line at top
#-- use exec to use exitcode (if any) directly from the tcl script
#exec /usr/bin/env tclsh "$0" "$@"
#-- alternative - can run sh/bash script after the tcl call.
/usr/bin/env tclsh "$0" "$@"
exitcode=$?
#echo "tcl exitcode: ${exitcode}"
#-- override exitcode example
#exit 66
#</shell-launch-tcl>
# -- --- --- --- --- --- --- ---
#<shell-payload-post-tcl>
#</shell-payload-post-tcl>
#printf "sh/bash done \n"
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end sh Payload
#------------------------------------------------------
fi
exit ${exitcode}
# end hide sh/bash block from Tcl
# This comment with closing brace should stay in place whether if commented or not }
#------------------------------------------------------
# begin hide powershell-block from Tcl - only needed if Tcl didn't exit or return above
if 0 {
: end heredoc1 - end hide from powershell \
'@
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- powershell/pwsh section
# --
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
function GetScriptName { $myInvocation.ScriptName }
$scriptname = getScriptName
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---begin powershell Payload
#"Timestamp : {0,10:yyyy-MM-dd HH:mm:ss}" -f $(Get-Date) | write-host
#"Script Name : {0}" -f $scriptname | write-host
#"Powershell Version: {0}" -f $PSVersionTable.PSVersion.Major | write-host
#"powershell args : {0}" -f ($args -join ", ") | write-host
# -- --- --- ---
#<powershell-payload-pre-tcl>
#</powershell-payload-pre-tcl>
# -- --- --- --- --- --- --- ---
#<powershell-launch-tcl>
tclsh $scriptname $args
#</powershell-launch-tcl>
# -- --- --- --- --- --- --- ---
#<powershell-payload-post-tcl>
#</powershell-payload-post-tcl>
# unbal }
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end powershell Payload
#"powershell reporting exitcode: {0}" -f $LASTEXITCODE | write-host
Exit $LASTEXITCODE
# heredoc2 for powershell to ignore block below
$1 = @'
'
: end hide powershell-block from Tcl \
# This comment with closing brace should stay in place whether 'if' commented or not }
: cmd exit label - return exitcode
:exit
: \
@REM @ECHO exitcode: !task_exitcode!
: \
@EXIT /B !task_exitcode!
# cmd has exited
: end heredoc2 \
'@
<#
# id:tailblock0
# -- powershell multiline comment
#>
<#
# id:tailblock1
# <ctrl-z>

# </ctrl-z>
# -- unreachable by tcl directly if ctrl-z character is in the <ctrl-z> section above. (but file can be read and split on \x1A)
# -- Potential for zip and/or base64 contents, but we can't stop pwsh parser from slurping in the data
# -- so for example a plain text tar archive could cause problems depending on the content.
# -- final line in file must be the powershell multiline comment terminator or other data it can handle.
# -- e.g plain # comment lines will work too
# -- (for example a powershell digital signature is a # commented block of data at the end of the file)
#>

57
src/modules/punk/mix/templates/utility/scriptappwrappers/punk-multishell.cmd

@ -1,14 +1,15 @@
set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershell;proc Hide s {proc $s args {}}; Hide :;rename set s2;Hide set;s2 1 list]"; set -- : "$@"; $1 = @'
: heredoc1 - hide from powershell (close sqote for unix shells) ' \
: << 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
: "[rename set s;proc Hide x {proc $x args {}};Hide :]" "\$(function : {<#pwsh#>})" ^
set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershell;proc Hide x {proc $x args {}}; Hide :;Hide <#;Hide set;s 1 list]"; set -- : "$@";$1 = @'
: heredoc1 - hide from powershell using @ and squote above. (close sqote for unix shells) ' \
: .bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl \
: "[Hide @ECHO; Hide ); Hide (;Hide echo]#not necessary but can help avoid errs in testing"
: "[Hide @ECHO; Hide ); Hide (;Hide echo; Hide @REM]#not necessary but can help avoid errs in testing"
: << 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
: Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
@REM {
@REM DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required and will reduce functionality.
@REM Even comment lines can be part of the functionality of this script - modify with care.
@REM Change the value of nextshell in the next line if desired, and code within payload sections as appropriate.
@SET "nextshell=pwsh"
@SET "nextshell=tclsh"
@REM nextshell set to pwsh,sh,bash or tclsh
@REM @ECHO nextshell is %nextshell%
@SET "validshells=pwsh,sh,bash,tclsh"
@ -17,24 +18,52 @@ set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershe
@REM ## ### ### ### ### ### ### ### ### ### ### ### ### ###
@REM -- cmd/batch file section (ignored on unix)
@REM -- This section intended only to launch the next shell
@REM -- Avoid customising this if possible. cmd/batch script is probably the least expressive language.
@REM -- custom windows payloads should be in powershell,tclsh or sh/bash code sections
@REM -- Avoid customising this if possible. cmd/batch script is probably the least expressive language and most error prone.
@REM -- custom windows payloads should be in powershell,tclsh (or sh/bash if available) code sections
@REM ## ### ### ### ### ### ### ### ### ### ### ### ### ###
@SETLOCAL EnableExtensions EnableDelayedExpansion
@SET "winpath=%~dp0"
@SET "fname=%~nx0"
@REM @ECHO fname %fname%
@REM @ECHO winpath %winpath%
@IF %nextshell%==pwsh (
@SET pwshtest_exitcode=99
@SET need_ps1=0
@REM we want the ps1 to exist even if the nextshell isn't powershell
@if not exist "%~dp0%~n0.ps1" (
@SET need_ps1=1
) ELSE (
fc "%~dp0%~n0.cmd" "%~dp0%~n0.ps1" >nul || goto different
@REM @ECHO "files same"
@SET need_ps1=0
@GOTO :pscontinue
:different
@REM @ECHO "files differ"
@SET need_ps1=1
)
:pscontinue
@IF !need_ps1!==1 (
CALL pwsh -nop -nol -c write-host "statusmessage: pwsh-found" >NUL
SET pwshtest_exitcode=!errorlevel!
if !pwshtest_exitcode!==0 (
CALL pwsh -nop -c set-executionpolicy -Scope CurrentUser RemoteSigned
COPY "%~dp0%~n0.cmd" "%~dp0%~n0.ps1" >NUL
) else (
CALL powershell -nop -c set-executionpolicy -Scope CurrentUser RemoteSigned
COPY "%~dp0%~n0.cmd" "%~dp0%~n0.ps1" >NUL
)
)
@IF %nextshell%==pwsh (
if !pwshtest_exitcode!==99 (
REM pws vs powershell hasn't been tested because we didn't need to copy cmd to ps1 this time
REM test availability of preferred option of powershell7+ pwsh
CALL pwsh -nop -nol -c write-host "statusmessage: pwsh-found" >NUL
SET pwshtest_exitcode=!errorlevel!
REM ECHO pwshtest_exitcode !pwshtest_exitcode!
IF !pwshtest_exitcode!==0 CALL pwsh -nop -nol "%~dp0%~n0.ps1" %* & SET task_exitcode=!errorlevel!
)
REM fallback to powershell if pwsh failed
IF NOT !pwshtest_exitcode!==0 (
IF !pwshtest_exitcode!==0 (
CALL pwsh -nop -nol "%~dp0%~n0.ps1" %* & SET task_exitcode=!errorlevel!
) ELSE (
REM CALL powershell -nop -nol -c write-host powershell-found
CALL powershell -nop -nol -file "%~dp0%~n0.ps1" %*
SET task_exitcode=!errorlevel!
@ -94,7 +123,7 @@ set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershe
# -- e.g tclsh filename.cmd
# --
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
rename set ""; rename s2 set; set k {-- "$@" "a}; if {[info exists ::env($k)]} {unset ::env($k)} ;# tidyup
rename set ""; rename s set; set k {-- "$@" "a}; if {[info exists ::env($k)]} {unset ::env($k)} ;# tidyup
Hide :exit;Hide {<#};Hide '@
namespace eval ::punk::multishell {
set last_script_root [file dirname [file normalize ${argv0}/__]]
@ -206,7 +235,9 @@ if 0 {
'@
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
# -- powershell/pwsh section
# --
# -- Do not edit if current file is the .ps1
# -- Edit the corresponding .cmd and it will autocopy
# -- unbalanced braces { } here *even in comments* will cause problems if there was no Tcl exit or return above
# ## ### ### ### ### ### ### ### ### ### ### ### ### ###
function GetScriptName { $myInvocation.ScriptName }
$scriptname = getScriptName
@ -231,8 +262,6 @@ tclsh $scriptname $args
#<powershell-payload-post-tcl>
#</powershell-payload-post-tcl>
# unbal }
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---end powershell Payload
#"powershell reporting exitcode: {0}" -f $LASTEXITCODE | write-host
Exit $LASTEXITCODE

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save