Browse Source
User-approved contract amendment replacing the day-1 file-relpath filter: one
directory-oriented pathglob semantics at every layer, with the ergonomics gap
closed in the syntax itself.
punk::path 0.4.0:
- *** as a whole segment matches ZERO or more segments (join-aware regex in
pathglob_as_re: an adjacent separator is absorbed into an optional group),
so X/*** = X and everything below - the subtree spelling; ***/f.txt matches
at any depth including the root.
- include separability fix: an exact or single-segment-glob full match no
longer sets allbelow (the deep walk previously dragged the whole subtree in
for X and X/* patterns; the zipfs walk was already separable).
- exclude separability fix (new exclude_state classifier, both walks): only
**|***-tail patterns prune the matched subtree; other matches exclude just
that directory's files - the **/_aside vs **/_aside/** argdoc distinction is
now real. Dead _path_matches_any removed.
- legacy bare-* include collapse removed (a * in -include-paths is the
one-below lattice form, not a match-everything alias; no caller used it).
- globmatchpath default-nocase driveletter exception rewritten as a direct
regex-head rewrite (the regex-text file-split broke on c:/***'s glued group
and accepted non-alpha drives).
- path.test +5 lattice/*** pins (40 total).
runtests.tcl:
- -include-paths/-exclude-paths pass through to treefilenames unchanged;
argdocs teach the separable X | X/* | X/** | X/*** lattice; directory and
file-name axes independent (tails); single-file targeting = exact dir
pattern + file tail.
- -serial-paths reconciled to the same directory-of-file reading (default now
modules/punk/console/*** modules/opunk/console/*** via
runtests_discovery::dir_matches_any) - the pre-existing file-path serial
matching was the other same-option-different-referent divergence.
- per-pattern zero-match stderr advisory (the X/**-for-subtree foot-gun points
at X/***).
- json report emitter: whitespace-padded entier-looking values now take the
quoted-escaped path ('string is entier -strict' accepts surrounding
whitespace - a failed test's "0\n" result_was embedded a raw newline and
truncated the parseable report line).
- testsupport/discovery.tcl now a thin passthrough (requires punk::path
0.4.0-); pathdiscovery.test rewritten to the directory-semantics contract
(22 tests incl. the X/** zero-match advisory characterization); AGENTS.md
targeting guidance swept to /*** across src/tests and src/modules/opunk.
Verification (native tclsh 9.0.3, piped, serialized): 45-probe matrix, path
suite 40/40, runner suite 22/22; vs the pre-G-093 baseline the default
discovery FILE SET differs by exactly the added runner suite and result
parity only by the five new path tests (+ that suite); mode parity -jobs 16
vs singleproc: PARITY ok (94/1037/failed=1 exec-14.3). Goal contract amended
in the detail file; full record there.
Claude-Session: https://claude.ai/code/session_01BNUVVkYq9vHa6G3S9a3XTZ
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
14 changed files with 598 additions and 296 deletions
@ -1,5 +1,6 @@
|
||||
0.3.0 |
||||
0.4.0 |
||||
#First line must be a semantic version number |
||||
#all other lines are ignored. |
||||
#0.4.0 - pathglob syntax: *** as a whole segment matches ZERO or more segments (X/*** = X and everything below; ***/f.txt matches f.txt at any depth incl root) - globmatchpath/pathglob_as_re/treefilenames (G-093); treefilenames include separability fix: an exact or single-segment-glob full match no longer sets allbelow (previously X or X/* dragged the whole subtree in via the deep walk; zipfs walk already separable); treefilenames exclude separability fix: only **|***-tail exclude patterns prune the subtree - other matches exclude just that folder's files and the walk continues below (both walks; previously any dir match pruned, contradicting the **/_aside vs **/_aside/** argdoc distinction); globmatchpath default-nocase driveletter rewrite now a direct regex-head rewrite (handles c:/*** glued-group form, restricts to alpha drives); treefilenames legacy bare-* include collapse removed (a * in -include-paths no longer means match-everything - it is the one-below lattice form; use **|***) |
||||
#0.3.0 - scriptlib_resolve: extensionless tcl scripts resolvable via first-line identification (new system::scriptfile_is_tcl helper - '# tcl' comment, tclsh/tclkit/wish shebang, or sh-trampoline); per-directory spelling order (exact name as called wins over .tcl-appended within each location, kit-internal dir precedence preserved); .kit added to known extensions (previously lib:x.kit wrongly searched x.kit.tcl); return dict keys reworked: scripttype (tcl/kit/py/pl/ps1/sh or empty) + notes added, scriptname now the matched relative name; directories no longer match a spelling (file isfile); now also used by app-punkshell/app_shellrun lib: handling (previously app-punkscript only) |
||||
#0.2.2 - added scriptlib_resolve: shared resolution policy for the lib:<script> prefix (kit-internal app/scriptlib first and not externally overridable, then scriptlib dirs relative to the executable); PUNKARGS argdoc namespace + registration added to the module |
||||
|
||||
@ -1,71 +1,55 @@
|
||||
#testsupport/discovery.tcl - test-file discovery and path-targeting filter for runtests.tcl |
||||
#added 2026-07-19 (agent, G-093) |
||||
#testsupport/discovery.tcl - test-file discovery for runtests.tcl |
||||
#added 2026-07-19, reworked to directory-oriented pass-through 2026-07-20 (agent, G-093) |
||||
# |
||||
#Discovery contract (the runner's -include-paths/-exclude-paths semantics): |
||||
# - the tree below the test base is walked unrestricted (punk::path::treefilenames with its |
||||
# default match-everything include, tailglobs applied per directory as before), then the |
||||
# tailbase-RELATIVE FILE PATHS are filtered against the include/exclude patterns using |
||||
# punk::path::globmatchpath (* within a segment, ? single char, ** spans segments). |
||||
# - a file is included when ANY include pattern matches its relative path, then dropped when |
||||
# ANY exclude pattern matches it - exclusion wins over inclusion for the same file. |
||||
# - matching FILE paths (not the directory containing them) means modules/punk/mix/** includes |
||||
# files sitting directly in modules/punk/mix as well as deeper ones, and an exact relative |
||||
# path is a valid single-file pattern. A bare directory path without a glob tail matches |
||||
# nothing (append /** for a subtree). |
||||
#Discovery contract: -include-paths/-exclude-paths patterns are handed to |
||||
#punk::path::treefilenames unchanged and carry ITS directory-oriented semantics - |
||||
#patterns match the DIRECTORY containing test files (tailbase-relative, forward |
||||
#slashes), with the deliberately separable forms: |
||||
# X files directly in X only |
||||
# X/* files in folders exactly one below X |
||||
# X/** files in the subtrees strictly below X (not files directly in X) |
||||
# X/*** files in X and everything below it <- the common subtree form |
||||
#File-tail globs (the runtests trailing arguments, default *.test) select FILENAMES |
||||
#within the contributing directories - the directory and filename axes are independent. |
||||
#-exclude-paths uses the same syntax; **|***-tail patterns prune the matched subtree, |
||||
#other matches exclude just that folder's files; exclusion wins over inclusion. |
||||
# |
||||
#Why the filter exists here rather than passing the patterns to treefilenames (G-093 root |
||||
#cause, 2026-07-19): treefilenames' own -include-paths matches the DIRECTORY containing |
||||
#files, and its documented X/** boundary semantics exclude files directly in X - so suites |
||||
#keeping .test files at the subtree root (e.g modules/punk/mix/testsuites/scriptwrap) were |
||||
#silently missed by X/** targeting. runtests' contract - like its -serial-paths matching - |
||||
#is file-path oriented, so the patterns are applied to the discovered relative paths instead. |
||||
#The walk is unpruned, but the default full run already walked the whole tree; the test tree |
||||
#is small. |
||||
#History (G-093): the 2026-07-19 increment instead filtered tailbase-relative FILE |
||||
#paths at the runtests layer, which fixed the X/** boundary miss but gave |
||||
#-include-paths a different meaning here than in treefilenames. Reworked at user |
||||
#direction 2026-07-20: punk::path 0.4.0 gained *** (zero or more segments) plus |
||||
#include/exclude separability fixes, so the runner passes patterns through and the |
||||
#pathglob semantics are identical everywhere. |
||||
# |
||||
#Sourced by runtests.tcl (parent side - discovery happens once, before any child processes) |
||||
#and by the runner-targeting regression suite (runner/testsuites/discovery/pathdiscovery.test). |
||||
#Caller must have module paths established before sourcing (bootsupport for the runner, |
||||
#the generated payload for suite child processes). |
||||
#Sourced by runtests.tcl (parent side - discovery happens once, before any child |
||||
#processes) and by the runner-targeting regression suite |
||||
#(runner/testsuites/discovery/pathdiscovery.test). Callers need module paths |
||||
#established before sourcing: bootsupport for the runner - which therefore needs the |
||||
#punk::path 0.4.0 snapshot for *** support - and the generated payload for suite |
||||
#child processes. |
||||
|
||||
package require punk::path |
||||
package require punk::path 0.4.0- |
||||
|
||||
namespace eval ::runtests_discovery {} |
||||
|
||||
proc ::runtests_discovery::filter_paths {relpaths include_patterns exclude_patterns} { |
||||
#pure filter over relative file paths - include when any include pattern matches, |
||||
#then exclusion wins. A literal ** include pattern matches every path (fast path). |
||||
set include_all [expr {"**" in $include_patterns}] |
||||
set kept [list] |
||||
foreach relpath $relpaths { |
||||
set include $include_all |
||||
if {!$include} { |
||||
foreach pat $include_patterns { |
||||
if {[punk::path::globmatchpath $pat $relpath]} { |
||||
set include 1 |
||||
break |
||||
} |
||||
} |
||||
} |
||||
if {!$include} { |
||||
continue |
||||
} |
||||
foreach pat $exclude_patterns { |
||||
if {[punk::path::globmatchpath $pat $relpath]} { |
||||
set include 0 |
||||
break |
||||
} |
||||
} |
||||
if {$include} { |
||||
lappend kept $relpath |
||||
} |
||||
} |
||||
return $kept |
||||
proc ::runtests_discovery::discover_testfiles {base include_patterns exclude_patterns tailglobs exclude_files} { |
||||
return [punk::path::treefilenames -directory $base -tailbase $base -include-paths $include_patterns -exclude-paths $exclude_patterns -exclude-files $exclude_files {*}$tailglobs] |
||||
} |
||||
|
||||
proc ::runtests_discovery::discover_testfiles {base include_patterns exclude_patterns tailglobs exclude_files} { |
||||
#walk everything below base (treefilenames' own include filtering deliberately unused - |
||||
#see header), then filter the relative paths. Result keeps treefilenames' natural sort |
||||
#order, so runner discovery order is unchanged from pre-G-093 default discovery. |
||||
set relpaths [punk::path::treefilenames -directory $base -tailbase $base -include-paths {**} -exclude-files $exclude_files {*}$tailglobs] |
||||
return [filter_paths $relpaths $include_patterns $exclude_patterns] |
||||
proc ::runtests_discovery::dir_matches_any {patterns filepath} { |
||||
#directory-of-file matching for post-discovery classification (-serial-paths and the |
||||
#per-pattern zero-match advisory): true when the directory containing filepath matches |
||||
#any pattern - the same directory-oriented reading the discovery patterns use. |
||||
set dir [file dirname $filepath] |
||||
if {$dir eq "."} { |
||||
#a file directly at the discovery base - its tailbase-relative directory is the |
||||
#empty string (matched by e.g bare *, ** and ***) |
||||
set dir "" |
||||
} |
||||
foreach pat $patterns { |
||||
if {[punk::path::globmatchpath $pat $dir]} { |
||||
return 1 |
||||
} |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
Loading…
Reference in new issue