BATsh

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

  - TEST FIX (t/0020-tilde-expansion.t): a failing TE01 or TE02 now
    prints $HOME, the reference path, the reached path, the marker, the
    shell diagnostic captured on STDERR, and (TE02) whether the target
    directory still existed, as TAP comments.  A "not ok" that says
    nothing else cannot be diagnosed from a CPAN Testers report, which is
    why the 0.10 FAIL could not be resolved without another release.

  - TEST FIX (t/0030-expansion-literals.t): EL16 carried the same
    pathname-string comparison, against Cwd::realpath() -- the exact form
    that had already failed once on Win32 -- and had simply not been
    reached by a smoker yet.  It now uses the marker probe as well.  No
    call to Cwd::realpath() is left in the suite.

  - TEST FIX (t/0020-tilde-expansion.t): the file used File::Spec without
    loading it, relying on FindBin to pull it in.  It is now imported
    explicitly.

  - NEW FILE t/lib/BATsh_TestOS.pm: the platform predicates the suite
    needs, named once and reviewed once, instead of re-derived inline in
    each .t file.  BATsh is a cmd.exe emulator, so its main platform is
    the one the author cannot smoke locally, and every Windows FAIL this
    distribution has received so far has been a test defect of exactly
    that shape: an assumption about Win32 written into a single case and
    never looked at again.  The module carries posix_file_semantics()
    (Win32 keeps neither the O_CREAT|O_EXCL-does-not-follow-a-symlink
    promise nor the mode bits), have_getpwnam(), fs_can_hold_name()
    (asks the file system whether a byte sequence can be a name at all,
    rather than assuming), dir_marker() / in_marked_dir() /
    drop_marker() / existing_entry() (the marker probe described above),
    tap_diag(), and is_windows() -- from which cygwin is deliberately
    absent, since it does keep the POSIX guarantees.

  - The file also states, as its header, the five rules those failures
    produced: R1 never compare pathnames as strings; R2 never assert on
    text the operating system produced (Windows error strings are
    localised -- assert on exit status); R3 never write an assertion
    that prints nothing when it fails; R4 skip with a printed reason
    where the platform cannot support the premise, and probe rather than
    test $^O at the call site; R5 a newly enabled case has never run on
    Windows.  They are in the test tree rather than in CONTRIBUTING
    because CONTRIBUTING is generated by pmake and would be overwritten,
    and because the place to find them is next to the code they govern.

  - t/0015, t/0019, t/0020 and t/0030 now use those predicates.  This is
    a consolidation, not a change of behaviour: t/0019 keeps the same
    skips through posix_file_semantics(), t/0015 CP12 replaces its
    hand-rolled probe with fs_can_hold_name(), t/0020 and t/0030 take
    the marker helpers and tap_diag().  One real gap closes with it --
    t/0020 TE03 resolves ~user and therefore needs getpwnam(), which
    native Windows perl does not implement; it now skips there with a
    reason instead of relying on the shell to fail for the right reason.

  - NEW FILE xt/win32_matrix.pl: a maintainer tool that runs the suite
    from one Windows box over the environments the smokers actually
    differ in -- five shapes of $HOME (backslash, forward slash,
    trailing separator, embedded space, and not set at all), a working
    directory on the same drive as $HOME and on another one (Windows
    keeps a current directory per drive), ANSI code page 932 and 65001,
    and any number of perls given with --perl=.  Each of the Windows
    FAILs this distribution has received would have been visible here
    before upload.  It is not part of "make test" and no installer or
    smoker runs it.

  - DOC FIX (lib/BATsh.pm, README): the SYNOPSIS and the description of
    BATsh->main() both stated that bin/batsh.pl "is installed as batsh".
    That holds only on Windows, where MakeMaker runs pl2bat over the
    installed script; EXE_FILES keeps the basename otherwise, so a Unix
    install puts it in the path as batsh.pl.  Confirmed with a DESTDIR
    install.  Both places now read "installed as batsh.pl; on Windows
    MakeMaker's pl2bat also provides batsh", and the command-line
    examples in the SYNOPSIS use the name that actually exists.

  - NEW FILE t/0000-environment.t: a report, not an assertion.  It has
    one case, that case always passes, and all it does is print what
    the machine actually is -- perl, archname, the spelling of $HOME
    and of the working directory and whether they share a volume,
    which of the environment variables that decide behaviour are set,
    whether STDIN and STDOUT are a console, whether getpwnam() and
    symlink() work, whether the file system folds case, whether it
    will accept a name carrying a CP932 trail byte of 0x5C -- as TAP
    comments, which every harness carries into the CPAN Testers
    report.  It is numbered 0000 so the fingerprint stands above
    whatever failed below it.  Four Windows FAILs have now arrived
    without any of this, and each cost a release to guess at; from
    here a report says what it was run on.  Nothing in this file
    should ever be turned into a check: a fingerprint that can fail is
    one more thing to diagnose rather than the means of diagnosing.

  - TEST FIX (t/0020-tilde-expansion.t): TE03 reads the EXIT STATUS of
    the failed "cd" instead of matching the text of its diagnostic.
    The text was BATsh's own literal and not the operating system's, so
    matching it did not breach rule R2 -- but it is indistinguishable
    from a breach at a glance, and it tied a passing case to a wording
    that is documentation rather than interface.  The getpwnam() skip
    goes with it: BATsh resolves ~user inside an eval and leaves an
    unresolvable one literal either way, so the case now exercises the
    same behaviour on a native Windows perl as on Unix instead of
    skipping there.

  - TEST FIX (t/lib/BATsh_TestOS.pm): existing_entry() now refuses any
    name that is also reachable from the current directory.  Such a
    name would be found by the relative probe whether the shell had
    moved or not, so t/0020 TE01 could pass without having tested
    anything -- and that is a real configuration, not a hypothesis: a
    smoker that sets $HOME to the build directory produces it.  Where
    no distinguishing entry exists the case now skips with a reason.
    A vacuous pass hides a case forever; a skip hides it for one run.

  - Two more rules in t/lib/BATsh_TestOS.pm, both drawn from the same
    four failures.  R6: "it passed on my Windows box" is not evidence,
    because every one of those FAILs passed a local run first -- the
    author's console has PERL5LIB, PERL5OPT, an interactive STDIN and
    a $HOME he chose, and a smoker has none of them.  R7: a green
    report must still say what it was green on.

  - NEW PREDICATES (t/lib/BATsh_TestOS.pm): have_symlink() (asks
    whether a link can actually be made in a given directory, since
    Win32 perl has had the function since 5.16 but fails without the
    privilege), writable_dir() (-w reports the read-only attribute on
    Win32 and says nothing about the ACL that decides), and
    path_shape() (names the properties of a pathname that have changed

Changes  view on Meta::CPAN


  - QA (pmake.bat 0.44 -> 0.45): runtime prerequisites were collected
    from lib/*.pm only, so a dependency that appeared solely in an
    installed bin/ script never reached META -- BATsh shipped without
    declaring FindBin, which bin/batsh.pl loads.  The scan now covers
    bin/*.pl as well, and the "lib" pragma is dropped from the result
    alongside strict, warnings and vars.

  - QA (pmake.bat 0.45 -> 0.46): the prerequisite scan matched "use
    Module" only, so a module reached through "require Module" was
    invisible to META.  BATsh loads Cwd and POSIX that way and declared
    neither.  Both spellings are now collected, and they are not treated
    alike: "use Module" and a bare "require Module" are unconditional and
    become runtime requires, while a require inside eval is the pure Perl
    way of writing "use this if it is here" -- the caller has a fallback
    -- and becomes a recommendation instead.  META.yml gains a
    "recommends" block (spec 1.4) and META.json a
    prereqs/runtime/recommends block (spec 2); Makefile.PL is unchanged,
    since a recommendation must not enter PREREQ_PM.  BATsh now declares
    Cwd and POSIX under recommends, which is what the code actually
    means.  The scan also skips POD and full-line comments, so prose that
    merely names a module can no longer invent a dependency.

  - QA (pmake.bat 0.46): "pmake dist" runs its own copy of the K1 rule
    over the sources listed in MANIFEST, and that copy did not say what
    INA_CPAN_Check::check_K says.  It exempted a comma followed by $, a
    single quote or a double quote, on the reasoning that stripping a
    string literal leaves a quote character behind -- but f("a","b")
    really is missing the space, and so is f($x,$y), so the exemption was
    hiding exactly the lines the rule exists to find.  The two are now
    spelled identically.  Nothing in BATsh changes: the strict form finds
    no violation anywhere in the set "pmake dist" scans.

  - QA (t/lib/INA_CPAN_Check.pm 0.42 -> 0.43): style group K ran over
    lib/*.pm alone.  Unlike D, E and G -- which demand a shape only a
    module is obliged to have -- K1, K2 and K3 ask for a space after a
    comma and for [ @array ] and { %hash } in place of \@array and
    \%hash, which are questions of spelling that apply to any Perl
    source.  Restricting them to lib/ left most of a pure-Perl
    distribution unchecked, so K now runs over lib/, bin/ and t/ as
    listed in MANIFEST.  Five lines needed respacing, none of which
    changes what the code does: t/0003 208, t/0005 40 and t/0009 273
    open(STDOUT,'>&...') in the STDOUT-capture helpers, and t/9080 55 68
    ok(0,"..."). With group K widened the suite runs 2071 tests.

  - QA (t/lib/INA_CPAN_Check.pm 0.43): new check B8.  B1 to B7 tie
    $VERSION to META.yml, META.json, Makefile.PL and Changes, but the
    "Version 0.00" line printed under =head1 VERSION was verified by
    nothing -- G2 asks only that the heading exists.  That line is what a
    reader sees on metacpan and it is a hand-edited copy of a number kept
    elsewhere, so it is precisely what goes stale unnoticed.  B8 requires
    every shipped Perl source carrying the heading -- lib/*.pm and the
    bin/*.pl installed as EXE_FILES -- to state the distribution version
    under it.  It is one check for the distribution, so check_B goes from
    six per module plus one to six per module plus two.

  - bin/batsh.pl: gains the =head1 VERSION section the five modules
    already carry, so the installed launcher documents which release it
    belongs to.  B8 above keeps it from drifting.

  - Changes: this entry is dated 2026-08-01 JST, the day of the upload.


0.09  2026-07-27 JST (Japan Standard Time)

  - FIX (SH, Windows): the result of an expansion is literal data, not
    shell source.  A line is expanded first and has its quotes removed
    afterwards, and the quote-removal stage could not tell text written
    in the script from text an expansion had just produced: every
    backslash coming out of a variable, a command substitution or a
    tilde expansion was re-read as a shell escape and deleted.  With
    HOME set to C:\home\flower,

        cd ~                     tried to enter  C:homeflower
        d="C:\Users\x" ; cd $d   tried to enter  C:Usersx

    so practically every Windows pathname that travelled through a
    variable was destroyed.  This is what made t/0020-tilde-expansion.t
    (TE01 TE02 TE04 TE07) fail in the CPAN Testers report for
    BATsh-0.08 on Windows with perl 5.8.9.

    POSIX quote removal applies to the source word only, never to the
    result of an expansion, and BATsh now follows that rule.  A
    backslash produced by an expansion is held behind a NUL-delimited
    sentinel -- a NUL can never occur in shell source -- until quote
    removal has finished, while a backslash written in the script keeps
    its escaping meaning.  Protected are all of $VAR, ${VAR} and the
    whole ${VAR...} family, array elements and ${arr[@]}, $1..$9, $@,
    $*, $0, $( ... ), `...` and tilde expansion; the literal backslash
    is restored again for the consumers that never dequote (external
    command lines, here-document bodies, the variable store).

    A tilde expansion is additionally protected against field
    splitting, so a home directory whose name contains a space stays a
    single word, as POSIX requires.

  - FIX (SH): "test" / "[" now removes quotes from its operands the
    same way command words do, instead of stripping one leading and one
    trailing double quote.  A half-stripped operand such as
    "C:\dir"/sub could never name an existing file.

  - FIX (SH): filename globbing keeps only names that exist.  When
    nothing matches, glob() hands the pattern back with its escape
    backslashes already removed, which silently turned an unmatched
    C:\dir\*.txt into C:dir*.txt.  POSIX leaves an unmatched pattern
    untouched, and so does BATsh now.

  - FIX (SH): "echo -e" interprets \n, \t, \r and \\ arriving from an
    expansion ("v='a\tb' ; echo -e $v") as well as from the source.

  - FIX (SH): "export VAR=value" stores the value rather than the quote
    characters around it.  "export V='C:\x'" used to export the quotes
    as part of the value, and "export V='a b'" was truncated at the
    space; the operands are now split on unquoted whitespace and
    dequoted exactly like an ordinary assignment.

  - FIX (SH and CMD, Windows): pathname expansion no longer goes
    through Perl's glob().  glob() reads a BACKSLASH AS AN ESCAPE
    character, so an ordinary Windows pattern

        d="C:\dir" ; for f in $d/*.txt ; do ... done



( run in 0.857 second using v1.01-cache-2.11-cpan-b16cb0d3907 )