{"thread":{"id":"63168","subject":"[PATCH 00/20] t: drop Perl as a mandatory prerequisite","startedAt":"2025-03-20T09:35:33Z","lastAt":"2025-07-07T09:53:31Z","messageCount":125,"participants":["Patrick Steinhardt","Eric Sunshine","Karthik Nayak","Phillip Wood","Johannes Schindelin","Junio C Hamano","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":20},"messages":[{"id":"514731","messageId":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":null,"subject":"[PATCH 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:27Z","receivedAt":"2025-03-20T09:35:33Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nwhile Git was initially building on Perl quite a lot, the significance\nof Perl has been dwindling over the years as more and more functionality\nwas converted into C builtins. Nowadays, an installation with Perl-based\nfeatures disabled is almost fully functional, only a handful of features\nremain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these features really are critical for day-to-day usage of Git,\nand most users probably wouldn't even notice if those features were not\ninstalled. Perl is thus very much optional nowadays.\n\nThere is one big exception though: it is impossible to run our test\nsuite without a Perl interpreter, so it is not easily possible to verify\nthat a Perl-less installation actually works as expected. For most of\nthe part though our test suite doesn't use all that much Perl, either.\nIt is present in a couple of critical paths, but those are easy to adapt\nto not use Perl anymore.\n\nThis is exactly what this patch series does: it refactors a couple of\ncentral parts in our test suite to not use Perl anymore so that it\nbecomes possible to run most of our tests entirely without Perl. Tests\nthat still depend on Perl are marked with a new PERL_TEST_HELPERS prereq\nso that they only execute when a Perl interpreter is available.\n\nWith this patch series, 30342 out of 31358 tests pass, which is around\n97% of our tests.\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (20):\n      t: skip chain lint when PERL_PATH is unset\n      t: refactor environment sanitization to not use Perl\n      t: adapt character translation helpers to not use Perl\n      t: adapt `test_copy_bytes()` to not use Perl\n      t: adapt `test_readlink()` to not use Perl\n      t: introduce PERL_TEST_HELPERS prerequisite\n      t: adapt existing PERL prerequisites\n      meson: stop requiring Perl when tests are enabled\n      Makefile: stop requiring Perl when running tests\n      t: refactor tests depending on Perl transliteration operator\n      t: refactor tests depending on Perl substitution operator\n      t: refactor tests depending on Perl to print data\n      t: refactor tests depending on Perl for textconv scripts\n      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n      t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n      t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n      t0021: refactor `generate_random_characters()` to not depend on Perl\n      t0210: refactor trace2 scrubbing to not use Perl\n      t5316: refactor `max_chain()` to not depend on Perl\n      t5703: refactor test to not depend on Perl\n\n meson.build                               |  2 +-\n t/Makefile                                | 16 +++++++--\n t/helper/test-path-utils.c                | 13 ++++++++\n t/helper/test-sha1.sh                     |  4 +--\n t/lib-diff.sh                             |  4 +--\n t/lib-gpg.sh                              |  6 +---\n t/lib-httpd.sh                            |  2 +-\n t/lib-httpd/apache.conf                   |  6 ++--\n t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------\n t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++\n t/lib-t6000.sh                            | 13 ++++----\n t/t0008-ignores.sh                        |  4 +--\n t/t0021-conversion.sh                     | 13 ++++----\n t/t0090-cache-tree.sh                     |  4 +--\n t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------\n t/t0210/scrub_normal.perl                 | 54 ------------------------------\n t/t0211-trace2-perf.sh                    |  6 ++++\n t/t0610-reftable-basics.sh                |  5 ++-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       | 16 +++++----\n t/t1007-hash-object.sh                    |  6 ++--\n t/t1010-mktree.sh                         |  4 +--\n t/t1450-fsck.sh                           |  6 ++--\n t/t3300-funny-names.sh                    |  6 ++--\n t/t4013-diff-various.sh                   |  6 ++++\n t/t4014-format-patch.sh                   | 30 ++++++++---------\n t/t4020-diff-external.sh                  |  2 +-\n t/t4029-diff-trailing-space.sh            |  3 +-\n t/t4030-diff-textconv.sh                  |  9 ++---\n t/t4031-diff-rewrite-binary.sh            | 17 ++++------\n t/t4058-diff-duplicates.sh                |  6 ++++\n t/t4103-apply-binary.sh                   |  6 ++--\n t/t4116-apply-reverse.sh                  |  4 +--\n t/t4150-am.sh                             |  8 ++---\n t/t4200-rerere.sh                         |  8 ++---\n t/t4205-log-pretty-formats.sh             |  6 ++--\n t/t4216-log-bloom.sh                      |  8 ++---\n t/t5004-archive-corner-cases.sh           |  6 ++++\n t/t5300-pack-object.sh                    | 10 +++---\n t/t5303-pack-corruption-resilience.sh     |  6 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               | 10 +++---\n t/t5318-commit-graph.sh                   | 12 +++----\n t/t5319-multi-pack-index.sh               | 16 ++++-----\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  4 +--\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  2 +-\n t/t5503-tagfollow.sh                      |  6 ++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++\n t/t5532-fetch-proxy.sh                    |  6 ++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  | 15 ++++-----\n t/t5551-http-fetch-smart.sh               |  7 ++++\n t/t5562-http-backend-content-length.sh    |  6 ++++\n t/t5601-clone.sh                          |  4 +--\n t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------\n t/t5701-git-serve.sh                      |  5 ++-\n t/t5702-protocol-v2.sh                    | 21 +++++++-----\n t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------\n t/t5710-promisor-remote-capability.sh     |  6 ++++\n t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---\n t/t6013-rev-list-reverse-parents.sh       | 10 +++---\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++\n t/t6115-rev-list-du.sh                    |  2 +-\n t/t6300-for-each-ref.sh                   | 15 ++++++---\n t/t7006-pager.sh                          |  6 ++--\n t/t7416-submodule-dash-url.sh             |  3 +-\n t/t7501-commit-basic-functionality.sh     |  6 ++--\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  9 ++---\n t/t8001-annotate.sh                       |  6 ++++\n t/t8002-blame.sh                          |  8 ++++-\n t/t8006-blame-textconv.sh                 |  2 +-\n t/t8011-blame-split-file.sh               |  6 ++--\n t/t8012-blame-colors.sh                   |  6 ++++\n t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib-functions.sh                   | 20 +++--------\n t/test-lib.sh                             | 49 +++++++++++++++++----------\n 84 files changed, 471 insertions(+), 373 deletions(-)\n\n\n---\nbase-commit: 683c54c999c301c2cd6f715c411407c413b1d84e\nchange-id: 20250317-b4-pks-t-perlless-138cf94696b8\n\n"},{"id":"514732","messageId":"20250320-b4-pks-t-perlless-v1-1-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 01/20] t: skip chain lint when PERL_PATH is unset","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:28Z","receivedAt":"2025-03-20T09:35:34Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our chainlint scripts verify that test files have proper '&&' chains.\nThese scripts are written in Perl and are executed for every test file\nbefore executing the test logic itself.\n\nIn subsequent commits we're about to refactor our test suite so that\nPerl becomes an optional dependency, only. And while it is already\npossible to disable this linter, developers that don't have Perl\navailable at all would always have to disable the linter manually, which\nis rather cumbersome.\n\nDisable the chain linter automatically in case PERL_PATH isn't set to\nmake this a bit less annoying. Bail out with an error in case the\ndeveloper has asked explicitly for the chain linter.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..1ce3b32fcac 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1523,6 +1523,22 @@ then\n \texport LSAN_OPTIONS\n fi\n \n+if test -z \"$PERL_PATH\"\n+then\n+\tcase \"${GIT_TEST_CHAIN_LINT:-unset}\" in\n+\tunset)\n+\t\tGIT_TEST_CHAIN_LINT=0\n+\t\t;;\n+\t0)\n+\t\t# The user has explicitly disabled the chain linter, so we\n+\t\t# don't have anything to worry about.\n+\t\t;;\n+\t*)\n+\t\tBAIL_OUT 'You need Perl for the chain linter'\n+\t\t;;\n+\tesac\n+fi\n+\n if test \"${GIT_TEST_CHAIN_LINT:-1}\" != 0 &&\n    test \"${GIT_TEST_EXT_CHAIN_LINT:-1}\" != 0\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514734","messageId":"20250320-b4-pks-t-perlless-v1-2-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 02/20] t: refactor environment sanitization to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:29Z","receivedAt":"2025-03-20T09:35:35Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Before executing tests we first sanitize the environment. Part of the\nsanitization is to unset a couple of environment variables that we know\nwill change the behaviour of Git. This is done with a small Perl script,\nwhich has the consequence that having a Perl interpreter available is a\nstrict requirement for running our unit tests.\n\nThe logic itself isn't particularly involved: we simply unset every\nenvironment variable whose key starts with 'GIT_', but then explicitly\nallow a subset of these.\n\nRefactor the logic to instead use sed(1) so that it becomes possible to\nexecute our tests without Perl.\n\nBased-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 32 ++++++++++++++------------------\n 1 file changed, 14 insertions(+), 18 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 1ce3b32fcac..a62699d6c79 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -499,24 +499,20 @@ EDITOR=:\n # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets\n # deriving from the command substitution clustered with the other\n # ones.\n-unset VISUAL EMAIL LANGUAGE $(\"$PERL_PATH\" -e '\n-\tmy @env = keys %ENV;\n-\tmy $ok = join(\"|\", qw(\n-\t\tTRACE\n-\t\tDEBUG\n-\t\tTEST\n-\t\t.*_TEST\n-\t\tPROVE\n-\t\tVALGRIND\n-\t\tUNZIP\n-\t\tPERF_\n-\t\tCURL_VERBOSE\n-\t\tTRACE_CURL\n-\t\tBUILD_DIR\n-\t));\n-\tmy @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);\n-\tprint join(\"\\n\", @vars);\n-')\n+unset VISUAL EMAIL LANGUAGE $(env | sed -n \\\n+\t-e '/^GIT_TRACE/d' \\\n+\t-e '/^GIT_DEBUG/d' \\\n+\t-e '/^GIT_TEST/d' \\\n+\t-e '/^GIT_.*_TEST/d' \\\n+\t-e '/^GIT_PROVE/d' \\\n+\t-e '/^GIT_VALGRIND/d' \\\n+\t-e '/^GIT_UNZIP/d' \\\n+\t-e '/^GIT_PERF_/d' \\\n+\t-e '/^GIT_CURL_VERBOSE/d' \\\n+\t-e '/^GIT_TRACE_CURL/d' \\\n+\t-e '/^GIT_BUILD_DIR/d' \\\n+\t-e 's/^\\(GIT_[^=]*\\)=.*/\\1/p'\n+)\n unset XDG_CACHE_HOME\n unset XDG_CONFIG_HOME\n unset GITPERLLIB\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514733","messageId":"20250320-b4-pks-t-perlless-v1-3-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 03/20] t: adapt character translation helpers to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:30Z","receivedAt":"2025-03-20T09:35:36Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of helper functions that translate characters, e.g.\nfrom LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl\nscripts, but they can be trivially adapted to instead use tr(1).\n\nNote that one specialty here is the handling of NUL characters in tr(1),\nwhich historically wasn't implemented correctly on all platforms. But\nquoting tr(1p):\n\n    It was considered that automatically stripping NUL characters from\n    the input was not correct functionality.  However, the removal of -n\n    in a later proposal does not remove the requirement that tr\n    correctly process NUL characters in its input stream.\n\nSo when tr(1) is implemented following the POSIX standard then it is\nexpected to handle the transliteration of NUL just fine.\n\nRefactor the helpers accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 79377bc0fc2..377f08a1428 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -88,15 +88,15 @@ test_decode_color () {\n }\n \n lf_to_nul () {\n-\tperl -pe 'y/\\012/\\000/'\n+\ttr '\\012' '\\000'\n }\n \n nul_to_q () {\n-\tperl -pe 'y/\\000/Q/'\n+\ttr '\\000' 'Q'\n }\n \n q_to_nul () {\n-\tperl -pe 'y/Q/\\000/'\n+\ttr 'Q' '\\000'\n }\n \n q_to_cr () {\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514735","messageId":"20250320-b4-pks-t-perlless-v1-4-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 04/20] t: adapt `test_copy_bytes()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:31Z","receivedAt":"2025-03-20T09:35:37Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_copy_bytes()` helper function copies up to N bytes from stdin\nto stdout. This is implemented using Perl, but it can be trivially\nadapted to instead use dd(1).\n\nRefactor the helper accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 12 +-----------\n 1 file changed, 1 insertion(+), 11 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 377f08a1428..c4b4d3a4c7f 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1640,17 +1640,7 @@ test_match_signal () {\n \n # Read up to \"$1\" bytes (or to EOF) from stdin and write them to stdout.\n test_copy_bytes () {\n-\tperl -e '\n-\t\tmy $len = $ARGV[1];\n-\t\twhile ($len > 0) {\n-\t\t\tmy $s;\n-\t\t\tmy $nread = sysread(STDIN, $s, $len);\n-\t\t\tdie \"cannot read: $!\" unless defined($nread);\n-\t\t\tlast unless $nread;\n-\t\t\tprint $s;\n-\t\t\t$len -= $nread;\n-\t\t}\n-\t' - \"$1\"\n+\tdd ibs=1 count=\"$1\" 2>/dev/null\n }\n \n # run \"$@\" inside a non-git directory\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514736","messageId":"20250320-b4-pks-t-perlless-v1-5-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 05/20] t: adapt `test_readlink()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:32Z","receivedAt":"2025-03-20T09:35:38Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_readlink()` helper function reads a symbolic link and returns\nthe path it is pointing to. It is thus equivalent to the readlink(1)\nutility, which isn't available on all supported platforms. As such, it\nis implemented using Perl so that we can use it even on platforms where\nthe shell utility isn't available.\n\nWhile using readlink(1) is not an option, what we can do is to implement\nthe logic ourselves in our test-tool. Do so, which allows a bunch of\ntests to pass when Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-path-utils.c | 13 +++++++++++++\n t/test-lib-functions.sh    |  2 +-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 72ac8d1b1b0..54d9ba98c0e 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc >= 2 && !strcmp(argv[1], \"readlink\")) {\n+\t\tstruct strbuf target = STRBUF_INIT;\n+\t\twhile (argc > 2) {\n+\t\t\tif (strbuf_readlink(&target, argv[2], 0) < 0)\n+\t\t\t\tdie_errno(\"cannot read link at '%s'\", argv[2]);\n+\t\t\tputs(target.buf);\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t}\n+\t\tstrbuf_release(&target);\n+\t\treturn 0;\n+\t}\n+\n \tif (argc >= 2 && !strcmp(argv[1], \"absolute_path\")) {\n \t\twhile (argc > 2) {\n \t\t\tputs(absolute_path(argv[2]));\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex c4b4d3a4c7f..bff8c4d1b41 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1979,7 +1979,7 @@ test_remote_https_urls() {\n # Print the destination of symlink(s) provided as arguments. Basically\n # the same as the readlink command, but it's not available everywhere.\n test_readlink () {\n-\tperl -le 'print readlink($_) for @ARGV' \"$@\"\n+\ttest-tool path-utils readlink \"$@\"\n }\n \n # Set mtime to a fixed \"magic\" timestamp in mid February 2009, before we\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514739","messageId":"20250320-b4-pks-t-perlless-v1-6-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:33Z","receivedAt":"2025-03-20T09:35:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"In the early days of Git, Perl was used quite prominently throughout the\nproject. This has changed significantly as almost all of the executables\nwe ship nowadays have eventually been rewritten in C. Only a handful of\nsubsystems remain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these subsystems can really be considered to be part of the\n\"core\" of Git, and an installation without them is fully functional.\nIt is more likely than not that an end user wouldn't even notice that\nany features are missing if those tools weren't installed. But while\nPerl nowadays very much is an optional dependency of Git, there is a\nsignificant limitation when Perl isn't available: developers cannot run\nour test suite.\n\nPreceding commits have started to lift this restriction by removing the\nstrict dependency on Perl in many central parts of the test library. But\nthere are still many tests that rely on small Perl helpers to do various\ndifferent things.\n\nIntroduce a new PERL_TEST_HELPERS prerequisite that guards all tests\nthat require Perl. This prerequisite is explicitly different than the\npreexisting PERL prerequisite:\n\n  - PERL records whether or not features depending on the Perl\n    interpreter are built.\n\n  - PERL_TEST_HELPERS records whether or not a Perl interpreter is\n    available for our tests.\n\nBy having these two separate prerequisites we can thus distinguish\nbetween tests that inherently depend on Perl because the underlying\nfeature does, and those tests that depend on Perl because the test\nitself is using Perl.\n\nAdapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        |  6 ++++++\n t/t0021-conversion.sh                     |  4 ++--\n t/t0210-trace2-normal.sh                  |  6 ++++++\n t/t0211-trace2-perf.sh                    |  6 ++++++\n t/t0610-reftable-basics.sh                |  2 +-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       |  2 +-\n t/t1007-hash-object.sh                    |  6 +++---\n t/t1010-mktree.sh                         |  4 ++--\n t/t1450-fsck.sh                           |  6 +++---\n t/t3300-funny-names.sh                    |  6 +++---\n t/t4013-diff-various.sh                   |  6 ++++++\n t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------\n t/t4020-diff-external.sh                  |  4 ++--\n t/t4029-diff-trailing-space.sh            |  2 +-\n t/t4030-diff-textconv.sh                  |  6 ++++++\n t/t4031-diff-rewrite-binary.sh            |  2 +-\n t/t4058-diff-duplicates.sh                |  6 ++++++\n t/t4103-apply-binary.sh                   |  6 ++++++\n t/t4116-apply-reverse.sh                  |  6 ++++++\n t/t4150-am.sh                             |  2 +-\n t/t4200-rerere.sh                         |  6 ++++++\n t/t4205-log-pretty-formats.sh             |  6 +++---\n t/t4216-log-bloom.sh                      |  8 ++++----\n t/t5004-archive-corner-cases.sh           |  6 ++++++\n t/t5300-pack-object.sh                    |  6 ++++++\n t/t5303-pack-corruption-resilience.sh     |  4 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               |  8 ++++----\n t/t5318-commit-graph.sh                   | 12 ++++++------\n t/t5319-multi-pack-index.sh               | 16 ++++++++--------\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  2 +-\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  4 ++--\n t/t5503-tagfollow.sh                      |  6 ++++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++++\n t/t5532-fetch-proxy.sh                    |  6 ++++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  |  2 +-\n t/t5551-http-fetch-smart.sh               |  7 +++++++\n t/t5562-http-backend-content-length.sh    |  6 ++++++\n t/t5601-clone.sh                          |  4 ++--\n t/t5616-partial-clone.sh                  |  6 +++---\n t/t5701-git-serve.sh                      |  2 +-\n t/t5702-protocol-v2.sh                    |  6 +++---\n t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++\n t/t5710-promisor-remote-capability.sh     |  6 ++++++\n t/t6002-rev-list-bisect.sh                |  6 ++++++\n t/t6003-rev-list-topo-order.sh            |  6 ++++++\n t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++\n t/t6013-rev-list-reverse-parents.sh       |  4 ++--\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++\n t/t6115-rev-list-du.sh                    |  6 ++++++\n t/t6300-for-each-ref.sh                   |  6 ++++++\n t/t7006-pager.sh                          |  2 +-\n t/t7416-submodule-dash-url.sh             |  6 ++++++\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  6 ++++++\n t/t8001-annotate.sh                       |  6 ++++++\n t/t8002-blame.sh                          |  6 ++++++\n t/t8006-blame-textconv.sh                 |  6 ++++++\n t/t8011-blame-split-file.sh               |  6 +++---\n t/t8012-blame-colors.sh                   |  6 ++++++\n t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib.sh                             |  1 +\n 71 files changed, 281 insertions(+), 93 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c9376dffb58..1aaa6bf5ae8 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,6 +5,12 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping ignores tests; Perl not available'\n+\ttest_done\n+fi\n+\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 3f6433d3045..9c3738ebb3f 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success 'required process filter should process multiple packets' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '\n \t)\n '\n \n-test_expect_success 'required process filter with clean error should fail' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex 4287ed3fbb3..ba4c0442b85 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\ndiff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh\nindex bac90465406..760cf69087f 100755\n--- a/t/t0211-trace2-perf.sh\n+++ b/t/t0211-trace2-perf.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_PERF_BRIEF\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 4618ffc108e..5e0a1fa176d 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success 'basic: can write large commit message' '\n+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \tperl -e \"\ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex e2708e11d5b..fa1e2f9eef8 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success 'small block size fails with large reflog message' '\n+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 398865d6ebe..a574da3df53 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1270,7 +1270,7 @@ extract_batch_output () {\n     ' \"$@\"\n }\n \n-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '\n+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '\n \tgit cat-file --batch-all-objects --batch >actual.raw &&\n \textract_batch_output $orig <actual.raw >actual &&\n \t{\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex a0481139de5..b3cf53ff8c9 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '\n \tgrep \"too-short tree object\" err\n '\n \n-test_expect_success 'malformed mode in tree' '\n+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"9100644 \\0$bin_oid\" >tree-with-malformed-mode &&\n@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '\n \tgrep \"malformed mode in tree entry\" err\n '\n \n-test_expect_success 'empty filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"100644 \\0$bin_oid\" >tree-with-empty-filename &&\n@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '\n \tgrep \"empty filename in tree entry\" err\n '\n \n-test_expect_success 'duplicate filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \t{\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex c291a2b33d7..4977998e205 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n \tperl -e \"print reverse <>\" <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n \tperl -e \"print reverse <>\" <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\ndiff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh\nindex 8a456b1142d..01050453762 100755\n--- a/t/t1450-fsck.sh\n+++ b/t/t1450-fsck.sh\n@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '\n \ttest_grep ! \"fatal: empty filename in tree entry\" out\n '\n \n-test_expect_success 'tree entry with type mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \ttest_when_finished \"remove_object \\$commit\" &&\n@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '\n \ttest_grep ! \"dangling blob\" out\n '\n \n-test_expect_success 'tree entry with bogus mode' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \tblob=$(echo blob | git hash-object -w --stdin) &&\n@@ -984,7 +984,7 @@ corrupt_index_checksum () {\n \n # Corrupt the checksum on the index and then\n # verify that only fsck notices.\n-test_expect_success 'detect corrupt index file in fsck' '\n+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '\n \tcp .git/index .git/index.backup &&\n \ttest_when_finished \"mv .git/index.backup .git/index\" &&\n \tcorrupt_index_checksum &&\ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex f5bf16abcd8..502b1572059 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'ls-files -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-index -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-tree -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 3855d68dbc0..782d97fb7df 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-diff.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff various tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \tGIT_AUTHOR_DATE=\"2006-06-26 00:00:00 +0000\" &&\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 884f83fb8a4..2782b1fc183 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF\n ---\n EOF\n \n-test_expect_success 'no threading' '\n+test_expect_success PERL_TEST_HELPERS 'no threading' '\n \tgit checkout side &&\n \tcheck_threading expect.no-threading main\n '\n@@ -466,11 +466,11 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread' '\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success '--thread overrides format.thread=deep' '\n+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n@@ -490,7 +490,7 @@ In-Reply-To: <1>\n References: <1>\n EOF\n \n-test_expect_success 'thread in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '\n \tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n \t\t--thread main\n '\n@@ -512,7 +512,7 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '\n \tcheck_threading expect.cover-letter --cover-letter --thread main\n '\n \n@@ -538,12 +538,12 @@ References: <1>\n \t<0>\n EOF\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread main\n '\n \n-test_expect_success 'thread explicit shallow' '\n+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=shallow main\n '\n@@ -562,7 +562,7 @@ References: <0>\n \t<1>\n EOF\n \n-test_expect_success 'thread deep' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep' '\n \tcheck_threading expect.deep --thread=deep main\n '\n \n@@ -584,7 +584,7 @@ References: <1>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '\n \tcheck_threading expect.deep-irt  --thread=deep \\\n \t\t--in-reply-to=\"<test.message>\" main\n '\n@@ -609,7 +609,7 @@ References: <0>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '\n \tcheck_threading expect.deep-cl --cover-letter --thread=deep main\n '\n \n@@ -638,27 +638,27 @@ References: <1>\n \t<3>\n EOF\n \n-test_expect_success 'thread deep cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '\n \tcheck_threading expect.deep-cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=deep main\n '\n \n-test_expect_success 'thread via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread via config' '\n \ttest_config format.thread true &&\n \tcheck_threading expect.thread main\n '\n \n-test_expect_success 'thread deep via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.deep main\n '\n \n-test_expect_success 'thread config + override' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + override' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success 'thread config + --no-thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.no-threading --no-thread main\n '\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex f1efe482a59..189294de7ef 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet\n \n echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n \n-test_expect_success 'force diff with \"diff\"' '\n+test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success 'diff --cached' '\n+test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex 32b6e9a4e76..a92a42990b1 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success \"$test_description\" '\n+test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex daebf9796f5..c7d8eb12453 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex c4394a27b56..cbe50b15772 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success 'rewrite diff respects textconv' '\n+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n \tgrep \"dissimilarity index\" diff &&\n \tgrep \"^-61\" diff &&\ndiff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh\nindex 2fce4a98977..16266dff2af 100755\n--- a/t/t4058-diff-duplicates.sh\n+++ b/t/t4058-diff-duplicates.sh\n@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff duplicates tests; Perl not available'\n+\ttest_done\n+fi\n+\n # make_tree_entry <mode> <mode> <sha1>\n #\n # We have to rely on perl here because not all printfs understand\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex d370ecfe0d9..4894605db7a 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping ignores tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 0784ba033a4..6f414ad27f5 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,6 +10,12 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply reverse tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 5e2b6c80eae..4794510d70d 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success 'am works with multi-line in-body headers' '\n+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex b0a3e849841..50fe8b0fd05 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rerere tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex f81e42a84d5..8f2ba98963f 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only \"key: value\" trail\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:unfold) unfolds trailers' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '\n \tgit log --no-walk --pretty=\"%(trailers:unfold)\" >actual &&\n \t{\n \t\tunfold <trailers &&\n@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success ':only and :unfold work together' '\n+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '\n \tgit log --no-walk --pretty=\"%(trailers:only,unfold)\" >actual &&\n \tgit log --no-walk --pretty=\"%(trailers:unfold,only)\" >reverse &&\n \ttest_cmp actual reverse &&\n@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '\n \tgit log --no-walk --pretty=\"format:%(trailers:key=Signed-Off-by,unfold)\" >actual &&\n \tunfold <trailers | grep Signed-off-by >expect &&\n \ttest_cmp expect actual\ndiff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh\nindex 3f163dc3969..8910d53cac1 100755\n--- a/t/t4216-log-bloom.sh\n+++ b/t/t4216-log-bloom.sh\n@@ -738,20 +738,20 @@ check_corrupt_graph () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'Bloom reader notices too-small data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '\n \tcheck_corrupt_graph BDAT clear 00000000 &&\n \techo \"warning: ignoring too-small changed-path chunk\" \\\n \t\t\"(4 < 12) in commit-graph file\" >expect.err &&\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '\n \tcheck_corrupt_graph BIDX 12 FFFFFFFF &&\n \t# use grep to avoid depending on exact chunk size\n \tgrep \"warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph\" err\n '\n \n-test_expect_success 'Bloom reader notices too-small index chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '\n \t# replace the index with a single entry, making most\n \t# lookups out-of-bounds\n \tcheck_corrupt_graph BIDX clear 00000000 &&\n@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-order index offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '\n \t# we do not know any real offsets, but we can pick\n \t# something plausible; we should not get to the point of\n \t# actually reading from the bogus offsets anyway.\ndiff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh\nindex 50344e17ca1..51749951916 100755\n--- a/t/t5004-archive-corner-cases.sh\n+++ b/t/t5004-archive-corner-cases.sh\n@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping archive corner cases tests; Perl not available'\n+\ttest_done\n+fi\n+\n # the 10knuls.tar file is used to test for an empty git generated tar\n # without having to invoke tar because an otherwise valid empty GNU tar\n # will be considered broken by {Open,Net}BSD tar\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 5ac8d39094b..143856c29f1 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,6 +7,12 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pack-object tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n \tperl -e \"print \\\"a\\\" x 4096;\" >a &&\ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex de58ca654a1..ac5e370e1e4 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first object' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n@@ -156,7 +156,7 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first delta' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 621bbbdd26e..81987296235 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex 32cf4227451..cd947b5a5ef 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -87,7 +87,7 @@ max_chain() {\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success 'packing produces a long delta' '\n+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth limits depth' '\n+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth=0 disables deltas' '\n+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'negative depth disables deltas' '\n+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\ndiff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh\nindex f68f64cd85e..0b3404f58fe 100755\n--- a/t/t5318-commit-graph.sh\n+++ b/t/t5318-commit-graph.sh\n@@ -837,7 +837,7 @@ check_corrupt_chunk () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \t# make it big enough that the graph file is plausible,\n \t# otherwise we hit an earlier check\n \tcheck_corrupt_chunk OIDF clear $(printf \"000000%02x\" $(test_seq 250)) &&\n@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices fanout/lookup table mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '\n \tcheck_corrupt_chunk OIDF 1020 \"FFFFFFFF\" &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph OID lookup chunk is the wrong size\n@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# Rather than try to corrupt a specific hash, we will just\n \t# wreck them all. But we cannot just set them all to 0xFFFFFFFF or\n \t# similar, as they are used for hi/lo starts in a binary search (so if\n@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small commit data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '\n \tcheck_corrupt_chunk CDAT clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph commit data chunk is wrong size\n@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds extra edge' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '\n \tcheck_corrupt_chunk EDGE clear &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph extra-edges pointer out of bounds\n@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small generations chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '\n \tcheck_corrupt_chunk GDA2 clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph generations chunk is wrong size\ndiff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh\nindex 0f215ad2e88..bd75dea9501 100755\n--- a/t/t5319-multi-pack-index.sh\n+++ b/t/t5319-multi-pack-index.sh\n@@ -1120,7 +1120,7 @@ corrupt_chunk () {\n \tcorrupt_chunk_file $midx \"$@\"\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \tcorrupt_chunk OIDF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small oid lookup chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '\n \tcorrupt_chunk OIDL clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small pack names chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '\n \t# There is no NUL to terminate the name here, so the\n \t# chunk is too short.\n \tcorrupt_chunk PNAM clear 70656666 &&\n@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader handles unaligned chunks' '\n+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '\n \t# A 9-byte PNAM means all of the subsequent chunks\n \t# will no longer be 4-byte aligned, but it is still\n \t# a valid one-pack chunk on its own (it is \"foo.pack\\0\").\n@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small object offset chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '\n \tcorrupt_chunk OOFF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader bounds-checks large offset table' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '\n \t# re-use the objects64 dir here to cheaply get access to a midx\n \t# with large offsets.\n \tgit init repo &&\n@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '\n \t)\n '\n \n-test_expect_success 'reader notices too-small revindex chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '\n \t# We only get a revindex with bitmaps (and likewise only\n \t# load it when they are asked for).\n \ttest_config repack.writeBitmaps true &&\n@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# This is similar to the out-of-bounds fanout test in t5318. The values\n \t# in adjacent entries should be large but not identical (they\n \t# are used as hi/lo starts for a binary search, which would then abort\ndiff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh\nindex a32be3867df..49a057cc2eb 100755\n--- a/t/t5324-split-commit-graph.sh\n+++ b/t/t5324-split-commit-graph.sh\n@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '\n \t)\n '\n \n-test_expect_success 'reader bounds-checks base-graph chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '\n \tgit clone --no-hardlinks . corrupt-base-chunk &&\n \t(\n \t\tcd corrupt-base-chunk &&\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex d27557b9b04..627f8b4efdc 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh\nindex a766a3e3f84..d8891e6a922 100755\n--- a/t/t5328-commit-graph-64bit-time.sh\n+++ b/t/t5328-commit-graph-64bit-time.sh\n@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '\n \tgit -C repo-uint32-max commit-graph verify\n '\n \n-test_expect_success 'reader notices out-of-bounds generation overflow' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '\n \tgraph=.git/objects/info/commit-graph &&\n \ttest_when_finished \"rm -rf $graph\" &&\n \tgit commit-graph write --reachable &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 3905cb6e4f1..1059ff45fe4 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\ndiff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh\nindex 3f81f16e133..571e8f1bc59 100755\n--- a/t/t5400-send-pack.sh\n+++ b/t/t5400-send-pack.sh\n@@ -268,7 +268,7 @@ extract_ref_advertisement () {\n \t'\n }\n \n-test_expect_success 'receive-pack de-dupes .have lines' '\n+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '\n \tgit init shared &&\n \tgit -C shared commit --allow-empty -m both &&\n \tgit clone -s shared fork &&\ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 0b28e4e452f..6a009fdcd71 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -20,7 +20,7 @@ extract_haves () {\n \tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n }\n \n-test_expect_success 'with core.alternateRefsCommand' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success 'with core.alternateRefsPrefixes' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nindex 845ca43ea0a..febe4410417 100755\n--- a/t/t5503-tagfollow.sh\n+++ b/t/t5503-tagfollow.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping tagfollow tests; Perl not available'\n+\ttest_done\n+fi\n+\n # End state of the repository:\n #\n #         T - tag1          S - tag2\ndiff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh\nindex 58074506c59..438250c75ed 100755\n--- a/t/t5504-fetch-receive-strict.sh\n+++ b/t/t5504-fetch-receive-strict.sh\n@@ -359,7 +359,7 @@ test_expect_success \\\n \tgrep \"Cannot demote unterminatedheader\" act\n '\n \n-test_expect_success 'badFilemode is not a strict error' '\n+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '\n \tgit init --bare badmode.git &&\n \ttree=$(\n \t\tcd badmode.git &&\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 5f350facf5e..432a2264e6f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -8,6 +8,12 @@ test_description='Per branch config variables affects \"git fetch\".\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-bundle.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch tests; Perl not available'\n+\ttest_done\n+fi\n+\n D=$(pwd)\n \n test_expect_success setup '\ndiff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh\nindex 37558226290..95d0f33b295 100755\n--- a/t/t5532-fetch-proxy.sh\n+++ b/t/t5532-fetch-proxy.sh\n@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch proxy tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup remote repo' '\n \tgit init remote &&\n \t(cd remote &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex c91a62b77af..342d0423c92 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 37f7547a4ca..77d20d19110 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\ndiff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh\nindex 761fdfcfe6c..b0d4ea78015 100755\n--- a/t/t5551-http-fetch-smart.sh\n+++ b/t/t5551-http-fetch-smart.sh\n@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n+\n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http fetch smart tests; Perl not available'\n+\ttest_done\n+fi\n+\n test \"$HTTP_PROTO\" = \"HTTP/2\" && enable_http2\n start_httpd\n \ndiff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh\nindex f3b158274c4..b6ee06f5c8f 100755\n--- a/t/t5562-http-backend-content-length.sh\n+++ b/t/t5562-http-backend-content-length.sh\n@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http backend content tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_lazy_prereq GZIP 'gzip --version'\n \n verify_http_result() {\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d0c18660e33..d743d986c40 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '\n \tgit -C replay.git index-pack -v --stdin <tmp.pack\n '\n \n-test_expect_success 'clone on case-insensitive fs' '\n+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '\n \tgit init icasefs &&\n \t(\n \t\tcd icasefs &&\n@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '\n \t)\n '\n \n-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '\n+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '\n \tgrep X icasefs/warning &&\n \tgrep x icasefs/warning &&\n \ttest_grep \"the following paths have collided\" icasefs/warning\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 46504519643..bc7e0fec8dc 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -751,7 +751,7 @@ replace_packfile () {\n \t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n }\n \n-test_expect_success 'upon cloning, check that all refs point to objects' '\n+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '\n+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 678a346ed06..200bf06ecb3 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'ignore very large set of prefixes' '\n+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex d3df81e7852..ad5e772cd72 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success 'when server sends \"ready\", expect DELIM' '\n+test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends \"ready\", expect DELIM' '\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n \tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n \ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex 191097171bc..f59d47aa6c6 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n+\ttest_done\n+fi\n+\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\ndiff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh\nindex d2cc69a17e4..9a420cf5605 100755\n--- a/t/t5710-promisor-remote-capability.sh\n+++ b/t/t5710-promisor-remote-capability.sh\n@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping promisor remote capabilities tests; Perl not available'\n+\ttest_done\n+fi\n+\n GIT_TEST_MULTI_PACK_INDEX=0\n GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0\n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex daa009c9a1b..5e1482aff78 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list bisect tests; Perl not available'\n+\ttest_done\n+fi\n+\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 0d7055d46d4..02dd4127aff 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list topo-order tests; Perl not available'\n+\ttest_done\n+fi\n+\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex bad02cf5b83..6131c361094 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 39793cbbd66..8074185742c 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success '--reverse --parents --full-history combines correctly' '\n+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n \tgit rev-list --parents --full-history main -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success '--boundary does too' '\n+test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n \tgit rev-list --boundary --parents --full-history main ^root -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 22dfd6d978e..eb98b3919c8 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list unexpected objects tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup well-formed objects' '\n \tblob=\"$(printf \"foo\" | git hash-object -w --stdin)\" &&\n \ttree=\"$(printf \"100644 blob $blob\\tfoo\" | git mktree)\" &&\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 3385fe9f130..6a74be576a2 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list disk usage tests; Perl not available'\n+\ttest_done\n+fi\n+\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex a5c77943854..732a4d3171e 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping for-each-ref tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 932c26cb45b..49aae183829 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success 'setup large log output' '\n+test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n \tperl -e \"\n \t\tprint \\\"this is a long commit message\\\" x 50000\n \t\" >commit-msg &&\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 0c605fd271a..14069600a2f 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping submodule dash URL tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex b2070d4e39f..14c41b2cb7c 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success 'status -z implies porcelain' '\n+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n \tgit status --porcelain |\n \tperl -pe \"s/\\012/\\000/g\" >expect &&\n \tgit status -z >output &&\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex 90ebb64f46e..b2730d200c8 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,6 +4,12 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping grep binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\ndiff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh\nindex d7167f55397..609845aeb1e 100755\n--- a/t/t8001-annotate.sh\n+++ b/t/t8001-annotate.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping annotate tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git annotate'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex e98993276a6..b40199df231 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 07a287ffd3e..5cb16872081 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,6 +4,12 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\ndiff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh\nindex c66494f5ba7..388057245c8 100755\n--- a/t/t8011-blame-split-file.sh\n+++ b/t/t8011-blame-split-file.sh\n@@ -81,7 +81,7 @@ do\n \t\tgit blame --root -C --$output combined >output\n \t'\n \n-\ttest_expect_success \"$output output finds correct commits\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output finds correct commits\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t5 base\n \t\t1 modified\n@@ -93,7 +93,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct filenames\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct filenames\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t11 one\n \t\t11 two\n@@ -102,7 +102,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct previous pointer\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct previous pointer\" '\n \t\tgenerate_expect >expect <<-EOF &&\n \t\t5 NONE\n \t\t1 $(git rev-parse modified^) one\ndiff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh\nindex c3a5f6d01ff..3d77352650f 100755\n--- a/t/t8012-blame-colors.sh\n+++ b/t/t8012-blame-colors.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex 067b15bad25..a9d38be997c 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success '(supposedly) non-conflicting change from SVN' '\n+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success 'change file but in unrelated area' \"\n+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n \tperl -i.bak -p -e 's/^4\\$/4444/' file &&\ndiff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh\nindex 40427883ec6..0781a8d6ace 100755\n--- a/t/t9350-fast-export.sh\n+++ b/t/t9350-fast-export.sh\n@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '\n \t(cd result && git show main:foo)\n '\n \n-test_expect_success 'fast-export quotes pathnames' '\n+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '\n \tgit init crazy-paths &&\n \ttest_config -C crazy-paths core.protectNTFS false &&\n \t(cd crazy-paths &&\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex 36566ace21b..f619b60f226 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'shell complains of overlong commands' '\n+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n \tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex a62699d6c79..59162a3c834 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1706,6 +1706,7 @@ test -n \"$USE_LIBPCRE2\" && test_set_prereq LIBPCRE2\n test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n test -n \"$SANITIZE_LEAK\" && test_set_prereq SANITIZE_LEAK\n test -n \"$GIT_VALGRIND_ENABLED\" && test_set_prereq VALGRIND\n+test -n \"$PERL_PATH\" && test_set_prereq PERL_TEST_HELPERS\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514737","messageId":"20250320-b4-pks-t-perlless-v1-7-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 07/20] t: adapt existing PERL prerequisites","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:34Z","receivedAt":"2025-03-20T09:35:40Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A couple of our tests depend on the PERL prerequisite even though it\nisn't needed. These tests fall into one of the following classes:\n\n  - The underlying logic used to be implemented in Perl but isn't\n    anymore. Here we can simply drop the dependency altogether.\n\n  - The test logic used to depend on Perl but doesn't anymore. Again, we\n    can simply drop the dependency.\n\n  - The test logic still relies on a Perl interpreter. These tests\n    should use the newly introduced PERL_TEST_HELPERS prerequisite.\n\nAdapt test cases accordingly.\n\nNote that in t1006 we have to introduce another new prerequisite\ndepending on whether or not the IPC::Open2 module is available. Funny\nenough, when starting to use `test_lazy_prereq` to do so we also get a\nconflict of variables with the \"script\" variable that contains the Perl\nlogic because `test_run_lazy_prereq_` also sets that variable. We thus\nrename the variable in t1006 to \"perl_script\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh                 | 10 +++++-----\n t/t0090-cache-tree.sh                 |  4 ++--\n t/t1006-cat-file.sh                   | 14 +++++++++-----\n t/t7501-commit-basic-functionality.sh |  6 +++---\n 4 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 9c3738ebb3f..4a892a91780 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'\n \t)\n '\n \n-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n+test_expect_success 'invalid process filter must fail (and not hang!)' '\n \ttest_config_global filter.protocol.process cat &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n@@ -1111,19 +1111,19 @@ do\n \tbranch) opt='-f HEAD' ;;\n \tesac\n \n-\ttest_expect_success PERL,TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress test_terminal git checkout $opt\n \t'\n \n-\ttest_expect_success PERL \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n+\ttest_expect_success \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! git checkout $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --quiet $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&\n \t\ttest_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt\n \t'\ndiff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh\nindex ab80c9ef135..d9015882946 100755\n--- a/t/t0090-cache-tree.sh\n+++ b/t/t0090-cache-tree.sh\n@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '\n \ttest_cache_tree\n '\n \n-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '\n+test_expect_success 'commit --interactive gives cache-tree on partial commit' '\n \ttest_when_finished \"git reset --hard\" &&\n \tcat <<-\\EOT >foo.c &&\n \tint foo()\n@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi\n \ttest_cache_tree expected.status\n '\n \n-test_expect_success PERL 'commit -p with shrinking cache-tree' '\n+test_expect_success 'commit -p with shrinking cache-tree' '\n \tmkdir -p deep/very-long-subdir &&\n \techo content >deep/very-long-subdir/file &&\n \tgit add deep &&\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex a574da3df53..0a22b0a7b8e 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '\n \tgrep \"^fatal:.*flush is only for --buffer mode.*\" err\n '\n \n-script='\n+perl_script='\n use warnings;\n use strict;\n use IPC::Open2;\n@@ -1345,12 +1345,16 @@ $? == 0 or die \"\\$?=$?\";\n \n expect=\"$hello_oid blob $hello_size\"\n \n-test_expect_success PERL '--batch-check is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-check $hello_oid \"$expect\"\n+test_lazy_prereq PERL_IPC_OPEN2 '\n+\tperl -MIPC::Open2 -e \"exit 0\"\n '\n \n-test_expect_success PERL '--batch-command info is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-check $hello_oid \"$expect\"\n+'\n+\n+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n '\n \n test_done\ndiff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh\nindex cc12f99f115..a37509f0043 100755\n--- a/t/t7501-commit-basic-functionality.sh\n+++ b/t/t7501-commit-basic-functionality.sh\n@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '\n \ttest_must_fail git commit -m foo -a file\n '\n \n-test_expect_success PERL 'can use paths with --interactive' '\n+test_expect_success 'can use paths with --interactive' '\n \techo bong-o-bong >file &&\n \t# 2: update, 1:st path, that is all, 7: quit\n \ttest_write_lines 2 1 \"\" 7 |\n@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '\n \tgrep Rubber.Duck output\n '\n \n-test_expect_success PERL 'interactive add' '\n+test_expect_success 'interactive add' '\n \techo 7 | test_must_fail git commit --interactive >out &&\n \tgrep \"What now\" out\n '\n \n-test_expect_success PERL \"commit --interactive doesn't change index if editor aborts\" '\n+test_expect_success \"commit --interactive doesn't change index if editor aborts\" '\n \techo zoo >file &&\n \ttest_must_fail git diff --exit-code >diff1 &&\n \ttest_write_lines u \"*\" q |\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514738","messageId":"20250320-b4-pks-t-perlless-v1-8-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 08/20] meson: stop requiring Perl when tests are enabled","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:35Z","receivedAt":"2025-03-20T09:35:42Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Perl interpreter used to be a strict dependency for running our test\nsuite. This requirement is explicit in the Meson build system, where we\nrequire Perl to be present unless tests have been disabled.\n\nWith the preceding commits we have loosened this restriction so that it\nis now possible to run tests when Perl is unavailable. Loosen the above\nrequirement accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/meson.build b/meson.build\nindex efe2871c9db..d6e27b236fa 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -772,7 +772,7 @@ endif\n # features. It is optional if you want to neither execute tests nor use any of\n # these optional features.\n perl_required = get_option('perl')\n-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n   perl_required = true\n endif\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514740","messageId":"20250320-b4-pks-t-perlless-v1-9-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 09/20] Makefile: stop requiring Perl when running tests","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:36Z","receivedAt":"2025-03-20T09:35:43Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Makefile for our tests has a couple of targets that depend on Perl.\nAdapt those targets to only run conditionally in case Perl is available\non the system so that it becomes possible to run the test suite without\nPerl.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/Makefile | 16 +++++++++++++---\n 1 file changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/t/Makefile b/t/Makefile\nindex 2994eb5fa9a..791e0a09789 100644\n--- a/t/Makefile\n+++ b/t/Makefile\n@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT\n \n all:: $(DEFAULT_TEST_TARGET)\n \n-test: pre-clean check-chainlint check-meson $(TEST_LINT)\n+test: pre-clean check-meson $(TEST_LINT)\n \t$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup\n \n+ifneq ($(PERL_PATH),)\n+test: check-chainlint\n+prove: check-chainlint\n+endif\n+\n failed:\n \t@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \\\n \t\tgrep -l '^failed [1-9]' *.counts | \\\n \t\tsed -n 's/\\.counts$$/.sh/p') && \\\n \ttest -z \"$$failed\" || $(MAKE) $$failed\n \n-prove: pre-clean check-chainlint $(TEST_LINT)\n+prove: pre-clean $(TEST_LINT)\n \t@echo \"*** prove (shell & unit tests) ***\"\n \t@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)\n \t$(MAKE) clean-except-prove-cache\n@@ -132,8 +137,13 @@ check-meson:\n \t\tfi; \\\n \tdone\n \n-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \\\n+test-lint: test-lint-duplicates test-lint-executable \\\n \ttest-lint-filenames\n+ifneq ($(PERL_PATH),)\n+test-lint: test-lint-shell-syntax\n+else\n+GIT_TEST_CHAIN_LINT = 0\n+endif\n ifneq ($(GIT_TEST_CHAIN_LINT),0)\n test-lint: test-chainlint\n endif\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514741","messageId":"20250320-b4-pks-t-perlless-v1-11-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:38Z","receivedAt":"2025-03-20T09:35:44Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform substitution via the\n\"s/\" operator. These usecases can be trivially replaced with sed(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        | 10 ++--------\n t/t4029-diff-trailing-space.sh            |  5 +++--\n t/t4200-rerere.sh                         | 12 +++---------\n t/t5303-pack-corruption-resilience.sh     | 10 ++++++----\n t/t5310-pack-bitmaps.sh                   |  4 ++--\n t/t5534-push-signed.sh                    |  4 ++--\n t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------\n t/t7416-submodule-dash-url.sh             |  9 ++-------\n t/t7508-status.sh                         |  4 ++--\n t/t8006-blame-textconv.sh                 |  8 +-------\n t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------\n 11 files changed, 40 insertions(+), 60 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex 1aaa6bf5ae8..7d5a0458818 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,12 +5,6 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping ignores tests; Perl not available'\n-\ttest_done\n-fi\n-\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\n@@ -45,11 +39,11 @@ test_stderr () {\n }\n \n broken_c_unquote () {\n-\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n+\t<\"$1\" sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' | tr '\\n' '\\0'\n }\n \n broken_c_unquote_verbose () {\n-\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n+\t<\"$1\" sed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' | tr ':\\t\\n' '\\000'\n }\n \n stderr_contains () {\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex a92a42990b1..db75998e35f 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n+test_expect_success \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\n@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tgit config --bool diff.suppressBlankEmpty true &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\n-\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n+\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n+\tmv exp.munged exp &&\n \tgit config --bool diff.suppressBlankEmpty false &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 7fcca9ddad5..bacb93d014f 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rerere tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\n@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n \ttest_might_fail git config --unset rerere.enabled &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep \"^=======\\$\" $rr/preimage &&\n \t! test -f $rr/postimage &&\n@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep ^=======$ $rr/preimage\n '\n@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n \tgit config rerere.enabled true &&\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1\n '\n \ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex ac5e370e1e4..07382797bbb 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n+test_expect_success 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n+\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n@@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n+test_expect_success 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n+\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \tgit cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 81987296235..9033d72b8c7 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -421,7 +421,7 @@ test_bitmap_cases () {\n \n \t\t\t# mark the commits which did not receive bitmaps as preferred,\n \t\t\t# and generate the bitmap again\n-\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n \t\t\t\tgit update-ref --stdin &&\n \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n \ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 342d0423c92..d5c0d00114e 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n \t# Tweak the push output to make the push option outside the cert\n \t# different, then replay it on a fresh dst, checking that ff is not\n \t# deleted.\n-\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n \tgit -C dst config receive.advertisepushoptions 1 &&\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex 6131c361094..12329aab388 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\n@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n    first_commit=$(git rev-parse HEAD~3)\n    '\n \n-test_expect_success 'corrupt second commit object' \\\n-   '\n-   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n-   test_must_fail git fsck --full\n-   '\n+test_expect_success 'corrupt second commit object' '\n+\tfor p in .git/objects/pack/*.pack\n+\tdo\n+\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n+\t\tmv \"$p.munged\" \"$p\" ||\n+\t\treturn 1\n+\tdone &&\n+\ttest_must_fail git fsck --full\n+'\n \n test_expect_success 'rev-list should fail' '\n \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 14069600a2f..00b81d349b9 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping submodule dash URL tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\n@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n '\n \n test_expect_success 'remove ./ protection from .gitmodules url' '\n-\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n+\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n+\tmv .gitmodules.munged .gitmodules &&\n \tgit commit -am \"drop protection\"\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 14c41b2cb7c..cdc1d6fcc78 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n+test_expect_success 'status -z implies porcelain' '\n \tgit status --porcelain |\n-\tperl -pe \"s/\\012/\\000/g\" >expect &&\n+\ttr \"\\012\" \"\\000\" >expect &&\n \tgit status -z >output &&\n \ttest_cmp expect output\n '\ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 5cb16872081..810dac18f56 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,12 +4,6 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping blame textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\n@@ -17,7 +11,7 @@ find_blame() {\n cat >helper <<'EOF'\n #!/bin/sh\n grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n-\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n+sed 's/^bin: /converted: /' <\"$1\"\n EOF\n chmod +x helper\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex a9d38be997c..9afdb45b1cc 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n+test_expect_success '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n \t(cd tmp &&\n-\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n-\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n+\t\tmv file.munged file &&\n \t\tpoke file &&\n \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n+test_expect_success 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n-\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n-\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n+\tsed -e 's/^4\\$/4444/' \\\n+\t    -e 's/^7\\$/7777/' \\\n+\t\t<file >file.munged &&\n+\tmv file.munged file &&\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n \tgit commit -m '4 => 4444, 7 => 7777' file &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514742","messageId":"20250320-b4-pks-t-perlless-v1-10-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 10/20] t: refactor tests depending on Perl transliteration operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:37Z","receivedAt":"2025-03-20T09:35:44Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform character\ntransliteration via the \"y/\" or \"tr/\" operator. These usecases can be\ntrivially replaced with tr(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-sha1.sh    |  4 ++--\n t/lib-diff.sh            |  4 ++--\n t/t3300-funny-names.sh   | 12 ++++++------\n t/t4020-diff-external.sh |  6 +++---\n t/t4103-apply-binary.sh  | 12 +++---------\n t/t4116-apply-reverse.sh | 10 ++--------\n t/t4200-rerere.sh        |  2 +-\n 7 files changed, 19 insertions(+), 31 deletions(-)\n\ndiff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh\nindex bf387d3db14..f03b784ddc2 100755\n--- a/t/helper/test-sha1.sh\n+++ b/t/helper/test-sha1.sh\n@@ -15,7 +15,7 @@ do\n \t\t\t{\n \t\t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\t\ttr \"\\000\" \"g\"\n \t\t\t} | ./t/helper/test-tool $sha1 $cnt\n \t\t)\n \t\tif test \"$expect\" = \"$actual\"\n@@ -61,7 +61,7 @@ do\n \t\t{\n \t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\ttr \"\\000\" \"g\"\n \t\t} | sha1sum |\n \t\tsed -e 's/ .*//'\n \t)\ndiff --git a/t/lib-diff.sh b/t/lib-diff.sh\nindex c4606bd4b7f..12b3c8fcc6a 100644\n--- a/t/lib-diff.sh\n+++ b/t/lib-diff.sh\n@@ -21,8 +21,8 @@ compare_diff_raw_z () {\n     # Also we do not check SHA1 hash generation in this test, which\n     # is a job for t0000-basic.sh\n \n-    perl -pe 'y/\\000/\\012/' <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n-    perl -pe 'y/\\000/\\012/' <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n+    tr \"\\000\" \"\\012\" <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n+    tr \"\\000\" \"\\012\" <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2\n }\n \ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex 502b1572059..dd0586b0073 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n+test_expect_success 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit ls-files -z >ls-files.z &&\n-\tperl -pe \"y/\\000/\\012/\" <ls-files.z >current &&\n+\ttr \"\\000\" \"\\012\" <ls-files.z >current &&\n \ttest_cmp expected current\n '\n \n@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n+test_expect_success 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-index -z --name-status $t0 >diff-index.z &&\n-\tperl -pe \"y/\\000/\\012/\" <diff-index.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-index.z >current &&\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n+test_expect_success 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-tree -z --name-status $t0 $t1 >diff-tree.z &&\n-\tperl -pe y/\\\\000/\\\\012/ <diff-tree.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-tree.z >current &&\n \ttest_cmp expected current\n '\n \ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex 189294de7ef..c8a23d51483 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet\n check_external_diff   1 empty  empty 1 on  --quiet\n check_external_diff 128 empty  error 2 on  --quiet\n \n-echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n+echo NULZbetweenZwords | tr \"Z\" \"\\000\" > file\n \n-test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n+test_expect_success 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n+test_expect_success 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex 4894605db7a..8e302a5a57e 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping ignores tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\n@@ -32,10 +26,10 @@ test_expect_success 'setup' '\n \tgit commit -m \"Initial Version\" 2>/dev/null &&\n \n \tgit checkout -b binary &&\n-\tperl -pe \"y/x/\\000/\" <file1 >file3 &&\n+\ttr \"x\" \"\\000\" <file1 >file3 &&\n \tcat file3 >file4 &&\n \tgit add file2 &&\n-\tperl -pe \"y/\\000/v/\" <file3 >file1 &&\n+\ttr \"y\" \"\\000\" <file3 >file1 &&\n \trm -f file2 &&\n \tgit update-index --add --remove file1 file2 file3 file4 &&\n \tgit commit -m \"Second Version\" &&\n@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '\n \ttest -z \"$(git diff --name-status binary -- file3)\"\n '\n \n-test_expect_success 'reject truncated binary diff' '\n+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '\n \tdo_reset &&\n \n \t# this length is calculated to get us very close to\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 6f414ad27f5..1e7beab0016 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,23 +10,17 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply reverse tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\n-\tperl -pe \"y/ijk/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"ijk\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit add file1 file2 &&\n \tgit commit -m initial &&\n \tgit tag initial &&\n \n \ttest_write_lines a b c g h i J K L m o n p q >file1 &&\n-\tperl -pe \"y/mon/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"mon\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit commit -a -m second &&\n \tgit tag second &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 50fe8b0fd05..7fcca9ddad5 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '\n \n test_expect_success 'rerere clear' '\n \tmv $rr/postimage .git/post-saved &&\n-\techo \"$sha1\ta1\" | perl -pe \"y/\\012/\\000/\" >.git/MERGE_RR &&\n+\techo \"$sha1\ta1\" | tr \"\\012\" \"\\000\" >.git/MERGE_RR &&\n \tgit rerere clear &&\n \t! test -d $rr\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514743","messageId":"20250320-b4-pks-t-perlless-v1-13-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:40Z","receivedAt":"2025-03-20T09:35:45Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of tests that depend on Perl for textconv scripts.\nRefactor these tests to instead be implemented via shell utilities so\nthat we can drop a couple of PERL_TEST_HELPERS prerequisites.\n\nNote that not all of the conversions are a one-to-one equivalent to the\nprevious textconv scripts. But that's not really needed in the first\nplace: we only care that the textconv script does something, and that\ncan be verified trivially without having a full-blown invocation of\nhexdump. So at times, the implementation of the textconv scripts is\nreduced to their bare minimum.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t4030-diff-textconv.sh       | 15 +++------------\n t/t4031-diff-rewrite-binary.sh | 19 +++++++------------\n t/t7815-grep-binary.sh         | 15 +++------------\n 3 files changed, 13 insertions(+), 36 deletions(-)\n\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex c7d8eb12453..f904fc19f69 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping diff textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\n@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n +1\n EOF\n \n-cat >hexdump <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-chmod +x hexdump\n-\n test_expect_success 'setup binary file with history' '\n+\twrite_script hexdump <<-\\EOF &&\n+\ttr \"\\000\\001\" \"01\" <\"$1\"\n+\tEOF\n \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n '\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex cbe50b15772..15e012ccc7c 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n \tgrep \" rewrite file\" diff\n '\n \n-{\n-\techo \"#!$SHELL_PATH\"\n-\tcat <<'EOF'\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-} >dump\n-chmod +x dump\n-\n test_expect_success 'setup textconv' '\n+\twrite_script dump <<-\\EOF &&\n+\ttest-tool hexdump <\"$1\"\n+\tEOF\n \techo file diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n+test_expect_success 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n-\tgrep \"dissimilarity index\" diff &&\n-\tgrep \"^-61\" diff &&\n-\tgrep \"^-0\" diff\n+\ttest_grep \"dissimilarity index\" diff &&\n+\ttest_grep \"^-3d 0a 00\" diff &&\n+\ttest_grep \"^+3d 0a 01\" diff\n '\n \n test_done\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex b2730d200c8..3bd91da9707 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,12 +4,6 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping grep binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\n@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n \ttest_cmp expect actual\n '\n \n-cat >nul_to_q_textconv <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n-EOF\n-chmod +x nul_to_q_textconv\n-\n test_expect_success 'setup textconv filters' '\n+\twrite_script nul_to_q_textconv <<-\\EOF &&\n+\ttr \"\\000\" \"Q\" <\"$1\"\n+\tEOF\n \techo a diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514744","messageId":"20250320-b4-pks-t-perlless-v1-12-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:39Z","receivedAt":"2025-03-20T09:35:45Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A bunch of tests rely on Perl to print data in various different ways.\nThese usages fall into the following categories:\n\n  - Print data conditionally by matching patterns. These usecases can be\n    converted to use awk(1) rather easily.\n\n  - Print data repeatedly. These usecases can typically be converted to\n    use a combination of `test-tool genzeros` and sed(1).\n\n  - Print data in reverse. These usecases can be converted to use\n    awk(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0610-reftable-basics.sh          |  7 +++----\n t/t0613-reftable-write-options.sh   |  4 ++--\n t/t1010-mktree.sh                   |  8 ++++----\n t/t4150-am.sh                       | 10 +++++-----\n t/t5300-pack-object.sh              | 16 +++++-----------\n t/t5326-multi-pack-bitmaps.sh       |  6 +++---\n t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------\n t/t5410-receive-pack-alternates.sh  |  6 +++---\n t/t5701-git-serve.sh                |  7 +++++--\n t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------\n t/t6115-rev-list-du.sh              |  8 +-------\n t/t7006-pager.sh                    |  8 ++++----\n t/t8002-blame.sh                    |  2 +-\n t/t9850-shell.sh                    |  4 ++--\n 14 files changed, 51 insertions(+), 67 deletions(-)\n\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 5e0a1fa176d..080797af1d0 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n+test_expect_success 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+\n+\tawk \"BEGIN { for (i = 0; i < 50000; i++) print \\\"this is a long commit message\\\" }\" >commit-msg &&\n \tgit -C repo commit --allow-empty --file=../commit-msg\n '\n \ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex fa1e2f9eef8..42aa1592f87 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n+test_expect_success 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\n \t\tcd repo &&\n \t\ttest_commit A &&\n-\t\tperl -e \"print \\\"a\\\" x 500\" >logmsg &&\n+\t\ttest-tool genzeros 500 | tr \"\\000\" \"a\" >logmsg &&\n \t\tcat >expect <<-EOF &&\n \t\tfatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large\n \t\tEOF\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex 4977998e205..e9973f74949 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n-\tperl -e \"print reverse <>\" <top |\n+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+\tsort -r <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n-\tperl -e \"print reverse <>\" <top.withsub |\n+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+\tsort -r <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\n '\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 4794510d70d..2ae93d3c967 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n+test_expect_success 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\n@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'\n     Body test\" --author=\"$LONG <long@example.com>\" &&\n \tgit format-patch --stdout -1 >patch &&\n \t# bump from, date, and subject down to in-body header\n-\tperl -lpe \"\n-\t\tif (/^From:/) {\n+\tawk \"\n+\t\t/^From:/{\n \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n \t\t\tprint \\\"Subject: x\\n\\\";\n-\t\t}\n-\t\" patch >msg &&\n+\t\t}; 1\n+\t\" <patch >msg &&\n \tgit checkout HEAD^ &&\n \tgit am msg &&\n \t# Ensure that the author and full message are present\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 143856c29f1..362b05441af 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,17 +7,11 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pack-object tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n-\tperl -e \"print \\\"a\\\" x 4096;\" >a &&\n-\tperl -e \"print \\\"b\\\" x 4096;\" >b &&\n-\tperl -e \"print \\\"c\\\" x 4096;\" >c &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"a\" >a &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"b\" >b &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"c\" >c &&\n \ttest-tool genrandom \"seed a\" 2097152 >a_big &&\n \ttest-tool genrandom \"seed b\" 2097152 >b_big &&\n \tgit update-index --add a a_big b b_big c &&\n@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'\n # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>\n # e.g.: check_deltas stderr -gt 0\n check_deltas() {\n-\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' <\"$1\") &&\n \tshift &&\n \tif ! test \"$deltas\" \"$@\"\n \tthen\n@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '\n \tcheck_unpack test-3-${packname_3} obj-list \"$BATCH_CONFIGURATION\"\n '\n \n-test_expect_success 'compare delta flavors' '\n+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '\n \tperl -e '\\''\n \t\tdefined($_ = -s $_) or die for @ARGV;\n \t\texit 1 if $ARGV[0] <= $ARGV[1];\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex 627f8b4efdc..e5d52de4bd3 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {\n \t\t\tcomm -13 bitmaps commits >before &&\n \t\t\ttest_line_count = 1 before &&\n \n-\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n-\t\t\t\t<before | git update-ref --stdin &&\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n+\t\t\tgit update-ref --stdin &&\n \n \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n \t\t\trm -fr $midx &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 1059ff45fe4..df13a18c5c7 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\n@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {\n \n tag_everything () {\n \tgit rev-list --all --no-object-names >in &&\n-\tperl -lne '\n-\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n-\t' <in | git update-ref --stdin\n+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' <in |\n+\tgit update-ref --stdin\n }\n \n test_expect_success 'setup' '\n@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n \ttest_config bitmapPseudoMerge.test.pattern \"refs/tags/\" &&\n \ttest_config bitmapPseudoMerge.test.maxMerges 1 &&\n \ttest_config bitmapPseudoMerge.test.stableThreshold never &&\n@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\t\ttest_commit_bulk 16 &&\n \n \t\t\tgit rev-list HEAD~16.. >in &&\n-\n-\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" <in |\n \t\t\tgit update-ref --stdin || return 1\n \t\tdone &&\n \n@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\tdo\n \t\t\ttest_pseudo_merge_commits $m >oids &&\n \t\t\tgrep -f oids refs |\n-\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n+\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n \t\t\tsort -u || return 1\n \t\tdone >remotes &&\n \ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 6a009fdcd71..4e82fd102e3 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -17,10 +17,10 @@ test_expect_success 'setup' '\n '\n \n extract_haves () {\n-\tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n+\tdepacketize | sed -n 's/^\\([^ ][^ ]*\\) \\.have/\\1/p'\n }\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n+test_expect_success 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n+test_expect_success 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 200bf06ecb3..d4c28bae39e 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n+test_expect_success 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\n@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t\techo command=ls-refs &&\n \t\techo object-format=$(test_oid algo) &&\n \t\techo 0001 &&\n-\t\tperl -le \"print \\\"ref-prefix refs/heads/\\$_\\\" for (1..65536)\" &&\n+\t\tawk \"{\n+\t\t\tfor (i = 1; i <= 65536; i++)\n+\t\t\t\tprint \\\"ref-prefix refs/heads/\\\", \\$i\n+\t\t}\" &&\n \t\techo 0000\n \t} |\n \ttest-tool pkt-line pack >in &&\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 8074185742c..273196f52b5 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n-\tgit rev-list --parents --full-history main -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+reverse () {\n+\tawk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'\n+}\n+\n+test_expect_success '--reverse --parents --full-history combines correctly' '\n+\tgit rev-list --parents --full-history main -- foo | reverse >expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n \t\t> actual &&\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n-\tgit rev-list --boundary --parents --full-history main ^root -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+test_expect_success '--boundary does too' '\n+\tgit rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\n \t\tmain ^root -- foo > actual &&\n \ttest_cmp expected actual\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 6a74be576a2..04c577dad69 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list disk usage tests; Perl not available'\n-\ttest_done\n-fi\n-\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\n@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '\n disk_usage_slow () {\n \tgit rev-list --no-object-names \"$@\" |\n \tgit cat-file --batch-check=\"%(objectsize:disk)\" |\n-\tperl -lne '$total += $_; END { print $total}'\n+\tawk '{ i += $1 } END { print i }'\n }\n \n # check behavior with given rev-list options; note that\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 49aae183829..9717e825f0d 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+test_expect_success 'setup large log output' '\n+\ttest-tool genzeros 50000 |\n+\ttr \"\\000\" \"a\" |\n+\tsed \"s/a/this is a long commit message/g\" >commit-msg &&\n \tgit commit --allow-empty -F commit-msg\n '\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex b40199df231..0b7548c8e75 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '\n \t\texpect=$1 && shift &&\n \t\techo $sha1 | cut -c 1-$expect >expect &&\n \t\tgit blame \"$@\" abbrev.t >actual &&\n-\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" <actual >actual.sha &&\n \t\ttest_cmp expect actual.sha\n \t}\n '\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex f619b60f226..21c3af48bd0 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n-\tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n+test_expect_success 'shell complains of overlong commands' '\n+\ttest-tool genzeros | tr \"\\000\" \"a\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514745","messageId":"20250320-b4-pks-t-perlless-v1-14-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:41Z","receivedAt":"2025-03-20T09:35:46Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\nstdin. Refactor it to instead use awk(1) so that we drop the\nPERL_TEST_HELPERS prerequisite in users of this library.\n\nNote that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\nnow that the test suite doesn't bail out early anymore in case the\nprerequisite isn't set.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-gpg.sh            |  6 +-----\n t/t6300-for-each-ref.sh | 21 ++++++++++-----------\n 2 files changed, 11 insertions(+), 16 deletions(-)\n\ndiff --git a/t/lib-gpg.sh b/t/lib-gpg.sh\nindex 3845b6ac449..937b876bd05 100644\n--- a/t/lib-gpg.sh\n+++ b/t/lib-gpg.sh\n@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '\n '\n \n sanitize_pgp() {\n-\tperl -ne '\n-\t\t/^-----END PGP/ and $in_pgp = 0;\n-\t\tprint unless $in_pgp;\n-\t\t/^-----BEGIN PGP/ and $in_pgp = 1;\n-\t'\n+\tsed \"/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}\"\n }\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 732a4d3171e..5db7038c417 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping for-each-ref tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\n@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '\n \ttest_must_fail git for-each-ref --format=\"%(raw)\" --tcl\n '\n \n-test_expect_success '%(raw) with --perl' '\n+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '\n \tgit for-each-ref --format=\"\\$name= %(raw);\n print \\\"\\$name\\\"\" refs/myblobs/blob1 --perl | perl >actual &&\n \tcmp blob1 actual &&\n@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '\n '\n \n test_trailer_option () {\n+\tif test \"$#\" -eq 3\n+\tthen\n+\t\tprereq=\"$1\"\n+\t\tshift\n+\tfi &&\n \ttitle=$1 option=$2\n \tcat >expect\n-\ttest_expect_success \"$title\" '\n+\ttest_expect_success $prereq \"$title\" '\n \t\tgit for-each-ref --format=\"%($option)\" refs/heads/main >actual &&\n \t\ttest_cmp expect actual &&\n \t\tgit for-each-ref --format=\"%(contents:$option)\" refs/heads/main >actual &&\n@@ -1452,7 +1451,7 @@ test_trailer_option () {\n \t'\n }\n \n-test_trailer_option '%(trailers:unfold) unfolds trailers' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \\\n \t'trailers:unfold' <<-EOF\n \t$(unfold <trailers)\n \n@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \\\n \n \tEOF\n \n-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \\\n \t'trailers:only,unfold' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n \tEOF\n \n-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \\\n \t'trailers:unfold,only' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514746","messageId":"20250320-b4-pks-t-perlless-v1-15-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:42Z","receivedAt":"2025-03-20T09:35:46Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `name_from_description()` test helper uses Perl to munge a given\ndescription and convert it into a name. Refactor it to instead use a\ncombination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\nprerequisites in users of this library.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-t6000.sh                 | 13 ++++++-------\n t/t6002-rev-list-bisect.sh     |  6 ------\n t/t6003-rev-list-topo-order.sh |  6 ------\n 3 files changed, 6 insertions(+), 19 deletions(-)\n\ndiff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\nindex fba6778ca35..5191ebb30b8 100644\n--- a/t/lib-t6000.sh\n+++ b/t/lib-t6000.sh\n@@ -109,13 +109,12 @@ check_output () {\n # All alphanums translated into -'s which are then compressed and stripped\n # from front and back.\n name_from_description () {\n-\tperl -pe '\n-\t\ts/[^A-Za-z0-9.]/-/g;\n-\t\ts/-+/-/g;\n-\t\ts/-$//;\n-\t\ts/^-//;\n-\t\ty/A-Z/a-z/;\n-\t'\n+\tsed \\\n+\t\t-e 's/[^A-Za-z0-9.]/-/g' \\\n+\t\t-e 's/--*/-/g' \\\n+\t\t-e 's/-$//' \\\n+\t\t-e 's/^-//' |\n+\ttr 'A-Z' 'a-z'\n }\n \n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex 5e1482aff78..daa009c9a1b 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list bisect tests; Perl not available'\n-\ttest_done\n-fi\n-\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 02dd4127aff..0d7055d46d4 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list topo-order tests; Perl not available'\n-\ttest_done\n-fi\n-\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514747","messageId":"20250320-b4-pks-t-perlless-v1-16-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 16/20] t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:43Z","receivedAt":"2025-03-20T09:35:47Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our Apache HTTPD setup exposes an \"one_time_perl\" endpoint to access\nrepositories. If used, we execute the \"apply-one-time-perl.sh\" CGI\nscript that checks whether we have a \"one-time-perl\" script. If so, that\nscript gets executed so that it can munge what would be served. Once\ndone, the script gets removed so that it doesn't execute a second time.\n\nAs the name says, this functionality expects the user to pass a Perl\nscript. This isn't really necessary though: we can just as easily\nimplement the same thing with arbitrary scripts.\n\nRefactor the code so that we instead expect an arbitrary script to\nexist and rename the functionality to \"one-time-script\". Adapt callers\nto use shell utilities instead of Perl so that we can drop the\nPERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-httpd.sh                       |  2 +-\n t/lib-httpd/apache.conf              |  6 ++---\n t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------\n t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++\n t/t5537-fetch-shallow.sh             | 17 ++++++-------\n t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------\n t/t5702-protocol-v2.sh               | 27 +++++++++++---------\n t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---\n 8 files changed, 86 insertions(+), 77 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex d83bafeab32..5091db949b7 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -165,7 +165,7 @@ prepare_httpd() {\n \tinstall_script broken-smart-http.sh\n \tinstall_script error-smart-http.sh\n \tinstall_script error.sh\n-\tinstall_script apply-one-time-perl.sh\n+\tinstall_script apply-one-time-script.sh\n \tinstall_script nph-custom-auth.sh\n \n \tln -s \"$LIB_HTTPD_MODULE_PATH\" \"$HTTPD_ROOT_PATH/modules\"\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex 022276a6b9a..e631ab0eb5e 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n-<LocationMatch /one_time_perl/>\n+<LocationMatch /one_time_script/>\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n ScriptAlias /error_smart/ error-smart-http.sh/\n ScriptAlias /error/ error.sh/\n-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1\n+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1\n ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Directory ${GIT_EXEC_PATH}>\n \tOptions FollowSymlinks\n@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Files error.sh>\n   Options ExecCGI\n </Files>\n-<Files apply-one-time-perl.sh>\n+<Files apply-one-time-script.sh>\n \tOptions ExecCGI\n </Files>\n <Files ${GIT_EXEC_PATH}/git-http-backend>\ndiff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh\ndeleted file mode 100644\nindex d7f9fed6aee..00000000000\n--- a/t/lib-httpd/apply-one-time-perl.sh\n+++ /dev/null\n@@ -1,27 +0,0 @@\n-#!/bin/sh\n-\n-# If \"one-time-perl\" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,\n-# using the contents of \"one-time-perl\" as the perl command to be run. If the\n-# response was modified as a result, delete \"one-time-perl\" so that subsequent\n-# HTTP responses are no longer modified.\n-#\n-# This can be used to simulate the effects of the repository changing in\n-# between HTTP request-response pairs.\n-if test -f one-time-perl\n-then\n-\tLC_ALL=C\n-\texport LC_ALL\n-\n-\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n-\t\"$PERL_PATH\" -pe \"$(cat one-time-perl)\" out >out_modified\n-\n-\tif cmp -s out out_modified\n-\tthen\n-\t\tcat out\n-\telse\n-\t\tcat out_modified\n-\t\trm one-time-perl\n-\tfi\n-else\n-\t\"$GIT_EXEC_PATH/git-http-backend\"\n-fi\ndiff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh\nnew file mode 100644\nindex 00000000000..b1682944e28\n--- /dev/null\n+++ b/t/lib-httpd/apply-one-time-script.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+# If \"one-time-script\" exists in $HTTPD_ROOT_PATH, run the script on the HTTP\n+# response. If the response was modified as a result, delete \"one-time-script\"\n+# so that subsequent HTTP responses are no longer modified.\n+#\n+# This can be used to simulate the effects of the repository changing in\n+# between HTTP request-response pairs.\n+if test -f one-time-script\n+then\n+\tLC_ALL=C\n+\texport LC_ALL\n+\n+\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n+\t./one-time-script out >out_modified\n+\n+\tif cmp -s out out_modified\n+\tthen\n+\t\tcat out\n+\telse\n+\t\tcat out_modified\n+\t\trm one-time-script\n+\tfi\n+else\n+\t\"$GIT_EXEC_PATH/git-http-backend\"\n+fi\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 77d20d19110..9dfcfb46df0 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\n@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before\n \tgit -C \"$REPO\" config protocol.version 2 &&\n \tgit -C client config protocol.version 2 &&\n \n-\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_perl/repo\" main:a_branch &&\n+\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_script/repo\" main:a_branch &&\n \n \t# Craft a situation in which the server sends back an unshallow request\n \t# with an empty packfile. This is done by refetching with a shorter\n \t# depth (to ensure that the packfile is empty), and overwriting the\n \t# shallow line in the response with the unshallow line we want.\n-\tprintf \"$(test_oid perl)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n-\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" <\"\\$1\"\n+\tEOF\n \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n-\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n+\t\tfetch --depth=1 \"$HTTPD_URL/one_time_script/repo\" \\\n \t\tmain:a_branch &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\" &&\n \n \t# Ensure that the resulting repo is consistent, despite our failure to\n \t# fetch.\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex bc7e0fec8dc..f878592a377 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -737,21 +737,25 @@ intersperse () {\n \tsed 's/\\(..\\)/'$1'\\1/g'\n }\n \n-# Create a one-time-perl command to replace the existing packfile with $1.\n+# Create a one-time-script command to replace the existing packfile with $1.\n replace_packfile () {\n-\t# The protocol requires that the packfile be sent in sideband 1, hence\n-\t# the extra \\x01 byte at the beginning.\n-\tcp $1 \"$HTTPD_ROOT_PATH/one-time-pack\" &&\n-\techo 'if (/packfile/) {\n-\t\tprint;\n-\t\tmy $length = -s \"one-time-pack\";\n-\t\tprintf \"%04x\\x01\", $length + 5;\n-\t\tprint `cat one-time-pack` . \"0000\";\n-\t\tlast\n-\t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\tcp \"$1\" one-time-pack &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tif grep packfile \"\\$1\" >/dev/null\n+\tthen\n+\t\tsed '/packfile/q' <\"\\$1\" &&\n+\t\t# The protocol requires that the packfile be sent in sideband\n+\t\t# 1, hence the extra \\001 byte at the beginning.\n+\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n+\t\tcat \"$PWD/one-time-pack\" &&\n+\t\tprintf \"0000\"\n+\telse\n+\t\tcat \"\\$1\"\n+\tfi\n+\tEOF\n }\n \n-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n+test_expect_success 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t\n \t# section header.\n \ttest_config -C \"$SERVER\" protocol.version 2 &&\n \ttest_must_fail git -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&\n \n \ttest_grep \"did not send all necessary objects\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not\n \n \t# Exercise to make sure it works.\n \tgit -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&\n \t! grep \"missing object referenced by\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \n \t# Clone. The client has deltabase_have but not deltabase_missing.\n \tgit -c protocol.version=2 clone --no-checkout \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo &&\n \tgit -C repo hash-object -w -- \"$SERVER/have.txt\" &&\n \n \t# Sanity check to ensure that the client does not have\n@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \tgrep \"want $(cat deltabase_missing)\" trace &&\n \t! grep \"want $(cat deltabase_have)\" trace &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n # DO NOT add non-httpd-specific tests here, because the last part of this\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex ad5e772cd72..27434b1f07a 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n+test_expect_success 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM'\n \n \t# After \"ready\" in the acknowledgments section, pretend that a FLUSH\n \t# (0000) was sent instead of a DELIM (0001).\n-\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/ready/{n;s/0001/0000/;}\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail git -C http_child -c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect\n \n \t# After the acknowledgments section, pretend that a DELIM\n \t# (0001) was sent instead of a FLUSH (0000).\n-\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n \t\t-c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \tgrep \"fetch< .*acknowledgments\" log &&\n \t! grep \"fetch< .*ready\" log &&\n \ttest_grep \"expected no other sections to be sent after no .ready.\" err\n@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n-\tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n+\tURI=\"$HTTPD_URL/one_time_script/server\" &&\n \n \tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n \n-\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n \t\t--no-tags \\\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex f59d47aa6c6..ac7266126a0 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '\n \t\ttest_commit m3 &&\n \t\tgit tag -d m2 m3\n \t) &&\n-\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo\" &&\n+\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo\" &&\n \tgit -C \"$LOCAL_PRISTINE\" config protocol.version 2\n '\n \n@@ -481,7 +481,9 @@ inconsistency () {\n \t# RPCs during a single negotiation.\n \toid1=$(git -C \"$REPO\" rev-parse $1) &&\n \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n-\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tsed \"s/$oid1/$oid2/\" <\"\\$1\"\n+\tEOF\n }\n \n test_expect_success 'server is initially ahead - no ref in want' '\n@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n-\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/main/rain/\" <\"$1\"\n+\tEOF\n \ttest_must_fail git -C local fetch 2>err &&\n \n \ttest_grep \"fatal: remote error: unknown ref refs/heads/rain\" err\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514748","messageId":"20250320-b4-pks-t-perlless-v1-17-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:44Z","receivedAt":"2025-03-20T09:35:49Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `generate_random_characters()` helper function generates N\nrandom characters in the range 'a-z' and writes them into a file. The\nlogic currently uses Perl, but it can be adapted rather easily by:\n\n  - Making `test-tool genrandom` generate an infinite stream.\n\n  - Using `tr -dc` to strip all characters which aren't in the range of\n    'a-z'.\n\n  - Using `test_copy_bytes()` to copy the first N bytes.\n\nThis allows us to drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 4a892a91780..bf10d253ec4 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -20,8 +20,7 @@ EOF\n generate_random_characters () {\n \tLEN=$1\n \tNAME=$2\n-\ttest-tool genrandom some-seed $LEN |\n-\t\tperl -pe \"s/./chr((ord($&) % 26) + ord('a'))/sge\" >\"$TEST_ROOT/$NAME\"\n+\ttest-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes \"$LEN\" >\"$TEST_ROOT/$NAME\"\n }\n \n filter_git () {\n@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n+test_expect_success 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n+test_expect_success 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514749","messageId":"20250320-b4-pks-t-perlless-v1-18-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 18/20] t0210: refactor trace2 scrubbing to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:45Z","receivedAt":"2025-03-20T09:35:50Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The output generated by our trace2 mechanism contains several fields\nthat are dependent on the environment they're being run in, which makes\nit somewhat harder to test it. As a countermeasure we scrub the output\nand strip out any fields that contain such information.\n\nThe logic to do so is implemented in Perl, but it can be trivially\nported to instead use sed(1). Refactor the code accordingly so that we\ncan drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------\n t/t0210/scrub_normal.perl | 54 -----------------------------------------\n 2 files changed, 43 insertions(+), 72 deletions(-)\n\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex ba4c0442b85..96c68f65df2 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping trace2 tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\n@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF\n #\n # Implicit return from cmd_<verb> function propagates <code>.\n \n+scrub_normal () {\n+\t# Scrub the variable fields from the normal trace2 output to make\n+\t# testing easier:\n+\t#\n+\t#   1. Various messages include an elapsed time in the middle of the\n+\t#      message. Replace the time with a placeholder to simplify our\n+\t#      HEREDOC in the test script.\n+\t#\n+\t#   2. We expect:\n+\t#\n+\t#        start <argv0> [<argv1> [<argv2> [...]]]\n+\t#\n+\t#      where argv0 might be a relative or absolute path, with or\n+\t#      without quotes, and platform dependent. Replace argv0 with a\n+\t#      token for HEREDOC matching in the test script.\n+\t#\n+\t#   3. Likewise, the 'cmd_path' message breaks out argv[0].\n+\t#\n+\t#      This line is only emitted when RUNTIME_PREFIX is defined,\n+\t#      so just omit it for testing purposes.\n+\t#\n+\t#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's\n+\t#      sake, skip it when parsing normal.\n+\tsed \\\n+\t\t-e 's/elapsed:[0-9]*\\.[0-9][0-9]*\\([eE][-+]\\{0,1\\}[0-9][0-9]*\\)\\{0,1\\}/elapsed:_TIME_/g' \\\n+\t\t-e \"s/^start '[^']*' \\(.*\\)/start _EXE_ \\1/\" \\\n+\t\t-e 's/^start [^ ][^ ]* \\(.*\\)/start _EXE_ \\1/' \\\n+\t\t-e '/^cmd_path/d' \\\n+\t\t-e '/^cmd_ancestry/d'\n+}\n+\n test_expect_success 'normal stream, return code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '\n test_expect_success 'normal stream, return code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 1\n@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '\n \ttest_when_finished \"rm -r traces actual expect\" &&\n \tmkdir traces &&\n \tGIT_TRACE2=\"$(pwd)/traces\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <\"$(ls traces/*)\" >actual &&\n+\tscrub_normal <\"$(ls traces/*)\" >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '\n test_expect_success 'normal stream, exit code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 0\n@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '\n test_expect_success 'normal stream, exit code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 1\n@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '\n test_expect_success 'normal stream, error event' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 003error \"hello world\" \"this is a test\" &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 003error '\\''hello world'\\'' '\\''this is a test'\\''\n@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '\n test_expect_success 'BUG messages are written to trace2' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 007bug &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 007bug\n@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 008bug\n@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 009bug_BUG\n@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 010bug_BUG\n@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '\n \ttest_config_global trace2.normalBrief 1 &&\n \ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '\n \tmv \"$(pwd)/.gitconfig\" \"$(pwd)/real.gitconfig\" &&\n \ttest_config_global include.path \"$(pwd)/real.gitconfig\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\ndiff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl\ndeleted file mode 100644\nindex 7cc4de392a0..00000000000\n--- a/t/t0210/scrub_normal.perl\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-#!/usr/bin/perl\n-#\n-# Scrub the variable fields from the normal trace2 output to\n-# make testing easier.\n-\n-use strict;\n-use warnings;\n-\n-my $float = '[0-9]*\\.[0-9]+([eE][-+]?[0-9]+)?';\n-\n-# This code assumes that the trace2 data was written with bare\n-# turned on (which omits the \"<clock> <file>:<line>\" prefix.\n-\n-while (<>) {\n-    # Various messages include an elapsed time in the middle\n-    # of the message.  Replace the time with a placeholder to\n-    # simplify our HEREDOC in the test script.\n-    s/elapsed:$float/elapsed:_TIME_/g;\n-\n-    my $line = $_;\n-\n-    # we expect:\n-    #    start <argv0> [<argv1> [<argv2> [...]]]\n-    #\n-    # where argv0 might be a relative or absolute path, with\n-    # or without quotes, and platform dependent.  Replace argv0\n-    # with a token for HEREDOC matching in the test script.\n-\n-    if ($line =~ m/^start/) {\n-\t$line =~ /^start\\s+(.*)/;\n-\tmy $argv = $1;\n-\t$argv =~ m/(\\'[^\\']*\\'|[^ ]+)\\s+(.*)/;\n-\tmy $argv_0 = $1;\n-\tmy $argv_rest = $2;\n-\n-\tprint \"start _EXE_ $argv_rest\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_path/) {\n-\t# Likewise, the 'cmd_path' message breaks out argv[0].\n-\t#\n-\t# This line is only emitted when RUNTIME_PREFIX is defined,\n-\t# so just omit it for testing purposes.\n-\t# print \"cmd_path _EXE_\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_ancestry/) {\n-\t# 'cmd_ancestry' is not implemented everywhere, so for portability's\n-\t# sake, skip it when parsing normal.\n-\t#\n-\t# print \"$line\";\n-    }\n-    else {\n-\tprint \"$line\";\n-    }\n-}\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514750","messageId":"20250320-b4-pks-t-perlless-v1-19-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 19/20] t5316: refactor `max_chain()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:46Z","receivedAt":"2025-03-20T09:35:51Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `max_chain()` helper function is used to extract the maximum delta\nchain of a packfile as printed by git-index-pack(1). The script uses\nPerl to extract that data, but it can be trivially refactored to use\nawk(1) instead.\n\nRefactor the helper accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5316-pack-delta-depth.sh | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex cd947b5a5ef..defaa06d650 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '\n \n max_chain() {\n \tgit index-pack --verify-stat-only \"$1\" >output &&\n-\tperl -lne '\n-\t  BEGIN { $len = 0 }\n-\t  /chain length = (\\d+)/ and $len = $1;\n-\t  END { print $len }\n-\t' output\n+\tawk '\n+\t\tBEGIN { len=0 }\n+\t\t/chain length = [0-9]+:/{ len=$4 }\n+\t\tEND { print len }\n+\t' <output | tr -d ':'\n }\n \n # Note that this whole setup is pretty reliant on the current\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n+test_expect_success 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n+test_expect_success '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n+test_expect_success '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n+test_expect_success 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514751","messageId":"20250320-b4-pks-t-perlless-v1-20-b1eefe27ac55@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH 20/20] t5703: refactor test to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-20T09:35:47Z","receivedAt":"2025-03-20T09:35:52Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We use Perl due to two different reasons in t5703:\n\n  - To filter advertised capabilities.\n\n  - To set up a CGI script with HTTPD.\n\nRefactor the first category to use `test_grep` instead. Refactoring the\nsecond category would be a bit more involved, so instead we add the\nPERL_TEST_HELPERS prerequisite to those individual tests now.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------\n 1 file changed, 8 insertions(+), 17 deletions(-)\n\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex ac7266126a0..1ab3191d72d 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n-\ttest_done\n-fi\n-\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\n@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '\n \n test_expect_success 'config controls ref-in-want advertisement' '\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant false &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant true &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_file_not_empty out.filter\n+\ttest_grep \"ref-in-want\" out\n '\n \n test_expect_success 'invalid want-ref line' '\n@@ -486,7 +477,7 @@ inconsistency () {\n \tEOF\n }\n \n-test_expect_success 'server is initially ahead - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '\n \ttest_grep \"fatal: remote error: upload-pack: not our ref\" err\n '\n \n-test_expect_success 'server is initially ahead - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server loses a ref - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"514798","messageId":"CAPig+cQ0ny060F1fdnCqZ=kALgMe5msxvKE-Dq+ECKxwwgfRFQ@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-1-b1eefe27ac55@pks.im","subject":"Re: [PATCH 01/20] t: skip chain lint when PERL_PATH is unset","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-20T18:36:36Z","receivedAt":"2025-03-20T18:36:48Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 20, 2025 at 5:35 AM Patrick Steinhardt <ps@pks.im> wrote:\n> Our chainlint scripts verify that test files have proper '&&' chains.\n\nIt's just a single script, so: s/scripts verify/script verifies/\n\n> These scripts are written in Perl and are executed for every test file\n\ns/These scripts/This script/\ns/are/is/g\n\n> before executing the test logic itself.\n>\n> In subsequent commits we're about to refactor our test suite so that\n> Perl becomes an optional dependency, only. And while it is already\n> possible to disable this linter, developers that don't have Perl\n> available at all would always have to disable the linter manually, which\n> is rather cumbersome.\n>\n> Disable the chain linter automatically in case PERL_PATH isn't set to\n> make this a bit less annoying. Bail out with an error in case the\n> developer has asked explicitly for the chain linter.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n\nNot worth a reroll, of course.\n"},{"id":"514799","messageId":"CAPig+cSPi0CV14o92FNFB0p2Z+nVTZ0mF67vd2ywsV6gGn7YSQ@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-6-b1eefe27ac55@pks.im","subject":"Re: [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-20T18:55:34Z","receivedAt":"2025-03-20T18:55:47Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:\n> [...]\n> Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests\n> that require Perl. This prerequisite is explicitly different than the\n> preexisting PERL prerequisite:\n> [...]\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n> diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\n> @@ -5,6 +5,12 @@ test_description=check-ignore\n> +if ! test_have_prereq PERL_TEST_HELPERS\n> +then\n> +       skip_all='skipping ignores tests; Perl not available'\n> +       test_done\n> +fi\n> diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\n> @@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n> +if ! test_have_prereq PERL_TEST_HELPERS\n> +then\n> +       skip_all='skipping ignores tests; Perl not available'\n> +       test_done\n> +fi\n\nThis message seems to have been copy/pasted. Should it be instead\n\"skipping apply-binary tests; Perl not available\"?\n"},{"id":"514800","messageId":"CAPig+cSC3zdur1fCsa7RMNZDcgUK4pUGKb22tpgdANxR6OxNMA@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-12-b1eefe27ac55@pks.im","subject":"Re: [PATCH 12/20] t: refactor tests depending on Perl to print data","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-20T19:33:44Z","receivedAt":"2025-03-20T19:33:56Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:\n> A bunch of tests rely on Perl to print data in various different ways.\n> These usages fall into the following categories:\n>\n>   - Print data conditionally by matching patterns. These usecases can be\n>     converted to use awk(1) rather easily.\n>\n>   - Print data repeatedly. These usecases can typically be converted to\n>     use a combination of `test-tool genzeros` and sed(1).\n>\n>   - Print data in reverse. These usecases can be converted to use\n>     awk(1).\n>\n> Refactor the tests accordingly so that we can drop a couple of\n> PERL_TEST_HELPERS prerequisites.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n> diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\n> @@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n> -test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n> +test_expect_success 'basic: can write large commit message' '\n>         test_when_finished \"rm -rf repo\" &&\n>         git init repo &&\n> -       perl -e \"\n> -               print \\\"this is a long commit message\\\" x 50000\n> -       \" >commit-msg &&\n> +\n> +       awk \"BEGIN { for (i = 0; i < 50000; i++) print \\\"this is a long commit message\\\" }\" >commit-msg &&\n>         git -C repo commit --allow-empty --file=../commit-msg\n>  '\n\nThe original Perl version emitted the entire message as a single-line,\nwhereas the awk replacement emits 50,000 lines. Was the intent of the\noriginal specifically to check whether it handled an extremely long\nline correctly, or was it merely checking whether an overall very\nlengthy content was handled correctly? If the former, then this\nsemantic change is inconsistent with what this test wants to be\nchecking; if the latter, then this semantic change is harmless.\n\nAlso, it is possible to do this entirely in shell without running an\nexternal program (assuming `test` and `printf` are builtins):\n\n  i=0 &&\n  while test $i -lt 50000\n  do\n    echo \"this is a long commit message\" &&\n    i=$(($i+1)) ||\n    return 1\n  done &&\n\n> diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\n> @@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n>                 echo object-format=$(test_oid algo) &&\n>                 echo 0001 &&\n> -               perl -le \"print \\\"ref-prefix refs/heads/\\$_\\\" for (1..65536)\" &&\n> +               awk \"{\n> +                       for (i = 1; i <= 65536; i++)\n> +                               print \\\"ref-prefix refs/heads/\\\", \\$i\n> +               }\" &&\n>                 echo 0000\n\nIn this one, the Perl version emitted 65,536 lines, so the awk version\nis consistent with that. Okay.\n\nThis could also be done purely in shell without using awk.\n"},{"id":"514801","messageId":"CAPig+cQdoZwY3u-xr49Jb8aaQmE69p4i4RUdy=cRv-V7VoWENg@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-13-b1eefe27ac55@pks.im","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-20T19:37:08Z","receivedAt":"2025-03-20T19:37:20Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> We have a couple of tests that depend on Perl for textconv scripts.\n> Refactor these tests to instead be implemented via shell utilities so\n> that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n>\n> Note that not all of the conversions are a one-to-one equivalent to the\n> previous textconv scripts. But that's not really needed in the first\n> place: we only care that the textconv script does something, and that\n> can be verified trivially without having a full-blown invocation of\n> hexdump. So at times, the implementation of the textconv scripts is\n> reduced to their bare minimum.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> +test_expect_success 'rewrite diff respects textconv' '\n>         git diff -B >diff &&\n> -       grep \"dissimilarity index\" diff &&\n> -       grep \"^-61\" diff &&\n> -       grep \"^-0\" diff\n> +       test_grep \"dissimilarity index\" diff &&\n> +       test_grep \"^-3d 0a 00\" diff &&\n> +       test_grep \"^+3d 0a 01\" diff\n>  '\n\nThis change seems unrelated to the stated purpose (`textconv`) of this patch(?).\n"},{"id":"514802","messageId":"CAPig+cTE1K6bt-4v9sv9ywF7wwc5Od8s5scnLsvYPFGBU5HDHg@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-15-b1eefe27ac55@pks.im","subject":"Re: [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-20T19:41:11Z","receivedAt":"2025-03-20T19:41:23Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> The `name_from_description()` test helper uses Perl to munge a given\n> description and convert it into a name. Refactor it to instead use a\n> combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\n> prerequisites in users of this library.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n> diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\n> @@ -109,13 +109,12 @@ check_output () {\n>  # All alphanums translated into -'s which are then compressed and stripped\n>  # from front and back.\n>  name_from_description () {\n> -       perl -pe '\n> -               s/[^A-Za-z0-9.]/-/g;\n> -               s/-+/-/g;\n> -               s/-$//;\n> -               s/^-//;\n> -               y/A-Z/a-z/;\n> -       '\n> +       sed \\\n> +               -e 's/[^A-Za-z0-9.]/-/g' \\\n> +               -e 's/--*/-/g' \\\n> +               -e 's/-$//' \\\n> +               -e 's/^-//' |\n> +       tr 'A-Z' 'a-z'\n>  }\n\nCan't you just use sed's `y//` function directly instead of having to\nseparately invoke a `tr` command?\n"},{"id":"514827","messageId":"CAOLa=ZR3V9e33oU5ard+eZLCUQgMybGwcj9PLMr7hy+4wNgM_Q@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-2-b1eefe27ac55@pks.im","subject":"Re: [PATCH 02/20] t: refactor environment sanitization to not use Perl","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2025-03-21T09:52:45Z","receivedAt":"2025-03-21T09:52:47Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Before executing tests we first sanitize the environment. Part of the\n> sanitization is to unset a couple of environment variables that we know\n> will change the behaviour of Git. This is done with a small Perl script,\n> which has the consequence that having a Perl interpreter available is a\n> strict requirement for running our unit tests.\n>\n> The logic itself isn't particularly involved: we simply unset every\n> environment variable whose key starts with 'GIT_', but then explicitly\n> allow a subset of these.\n>\n> Refactor the logic to instead use sed(1) so that it becomes possible to\n> execute our tests without Perl.\n>\n> Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/test-lib.sh | 32 ++++++++++++++------------------\n>  1 file changed, 14 insertions(+), 18 deletions(-)\n>\n> diff --git a/t/test-lib.sh b/t/test-lib.sh\n> index 1ce3b32fcac..a62699d6c79 100644\n> --- a/t/test-lib.sh\n> +++ b/t/test-lib.sh\n> @@ -499,24 +499,20 @@ EDITOR=:\n>  # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets\n>  # deriving from the command substitution clustered with the other\n>  # ones.\n> -unset VISUAL EMAIL LANGUAGE $(\"$PERL_PATH\" -e '\n> -\tmy @env = keys %ENV;\n> -\tmy $ok = join(\"|\", qw(\n> -\t\tTRACE\n> -\t\tDEBUG\n> -\t\tTEST\n> -\t\t.*_TEST\n> -\t\tPROVE\n> -\t\tVALGRIND\n> -\t\tUNZIP\n> -\t\tPERF_\n> -\t\tCURL_VERBOSE\n> -\t\tTRACE_CURL\n> -\t\tBUILD_DIR\n> -\t));\n> -\tmy @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);\n> -\tprint join(\"\\n\", @vars);\n> -')\n> +unset VISUAL EMAIL LANGUAGE $(env | sed -n \\\n> +\t-e '/^GIT_TRACE/d' \\\n> +\t-e '/^GIT_DEBUG/d' \\\n> +\t-e '/^GIT_TEST/d' \\\n> +\t-e '/^GIT_.*_TEST/d' \\\n> +\t-e '/^GIT_PROVE/d' \\\n> +\t-e '/^GIT_VALGRIND/d' \\\n> +\t-e '/^GIT_UNZIP/d' \\\n> +\t-e '/^GIT_PERF_/d' \\\n> +\t-e '/^GIT_CURL_VERBOSE/d' \\\n> +\t-e '/^GIT_TRACE_CURL/d' \\\n> +\t-e '/^GIT_BUILD_DIR/d' \\\n\nSo we delete all of the following from the stream of env.\n\n> +\t-e 's/^\\(GIT_[^=]*\\)=.*/\\1/p'\n\nBut any other `GIT_*` env variable is printed to be `unset`. Ok makes\nsense. This is much more readable than the perl version!\n\n> +)\n>  unset XDG_CACHE_HOME\n>  unset XDG_CONFIG_HOME\n>  unset GITPERLLIB\n>\n> --\n> 2.49.0.472.ge94155a9ec.dirty\n"},{"id":"514828","messageId":"CAOLa=ZRMLs55mwrcQPOFcHFxxDxv-a8fw9_RUV6ut6GYLoCQGw@mail.gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-4-b1eefe27ac55@pks.im","subject":"Re: [PATCH 04/20] t: adapt `test_copy_bytes()` to not use Perl","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2025-03-21T09:56:56Z","receivedAt":"2025-03-21T09:56:58Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The `test_copy_bytes()` helper function copies up to N bytes from stdin\n> to stdout. This is implemented using Perl, but it can be trivially\n> adapted to instead use dd(1).\n>\n> Refactor the helper accordingly, which allows a bunch of tests to pass\n> when Perl is not available.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/test-lib-functions.sh | 12 +-----------\n>  1 file changed, 1 insertion(+), 11 deletions(-)\n>\n> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> index 377f08a1428..c4b4d3a4c7f 100644\n> --- a/t/test-lib-functions.sh\n> +++ b/t/test-lib-functions.sh\n> @@ -1640,17 +1640,7 @@ test_match_signal () {\n>\n>  # Read up to \"$1\" bytes (or to EOF) from stdin and write them to stdout.\n>  test_copy_bytes () {\n> -\tperl -e '\n> -\t\tmy $len = $ARGV[1];\n> -\t\twhile ($len > 0) {\n> -\t\t\tmy $s;\n> -\t\t\tmy $nread = sysread(STDIN, $s, $len);\n> -\t\t\tdie \"cannot read: $!\" unless defined($nread);\n> -\t\t\tlast unless $nread;\n> -\t\t\tprint $s;\n> -\t\t\t$len -= $nread;\n> -\t\t}\n> -\t' - \"$1\"\n> +\tdd ibs=1 count=\"$1\" 2>/dev/null\n>  }\n>\n\nReally nice!\n\n>  # run \"$@\" inside a non-git directory\n>\n> --\n> 2.49.0.472.ge94155a9ec.dirty\n"},{"id":"514919","messageId":"Z-FUEhraLaDODbmO@pks.im","threadId":"63168","inReplyTo":"CAPig+cQdoZwY3u-xr49Jb8aaQmE69p4i4RUdy=cRv-V7VoWENg@mail.gmail.com","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-24T12:46:10Z","receivedAt":"2025-03-24T12:46:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:\n> On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > We have a couple of tests that depend on Perl for textconv scripts.\n> > Refactor these tests to instead be implemented via shell utilities so\n> > that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n> >\n> > Note that not all of the conversions are a one-to-one equivalent to the\n> > previous textconv scripts. But that's not really needed in the first\n> > place: we only care that the textconv script does something, and that\n> > can be verified trivially without having a full-blown invocation of\n> > hexdump. So at times, the implementation of the textconv scripts is\n> > reduced to their bare minimum.\n> >\n> > Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> > ---\n> > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> > +test_expect_success 'rewrite diff respects textconv' '\n> >         git diff -B >diff &&\n> > -       grep \"dissimilarity index\" diff &&\n> > -       grep \"^-61\" diff &&\n> > -       grep \"^-0\" diff\n> > +       test_grep \"dissimilarity index\" diff &&\n> > +       test_grep \"^-3d 0a 00\" diff &&\n> > +       test_grep \"^+3d 0a 01\" diff\n> >  '\n> \n> This change seems unrelated to the stated purpose (`textconv`) of this patch(?).\n\nNot quite. The test previously didn't run because it depends on the\nPerl-based textconv script. Now that this textconv script was adapted\nto use shell scripting instead it can run, but as explained in the\ncommit message the output of the textconv script changed. We don't\nreally care for the exact output at all, we only care that textconv did\nits thing. But we do have to adapt the test accordingly.\n\nPatrick\n"},{"id":"514920","messageId":"Z-FUGuLAiAq87pHx@pks.im","threadId":"63168","inReplyTo":"CAPig+cSPi0CV14o92FNFB0p2Z+nVTZ0mF67vd2ywsV6gGn7YSQ@mail.gmail.com","subject":"Re: [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-24T12:46:18Z","receivedAt":"2025-03-24T12:46:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Mar 20, 2025 at 02:55:34PM -0400, Eric Sunshine wrote:\n> On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > [...]\n> > Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests\n> > that require Perl. This prerequisite is explicitly different than the\n> > preexisting PERL prerequisite:\n> > [...]\n> > Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> > ---\n> > diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\n> > @@ -5,6 +5,12 @@ test_description=check-ignore\n> > +if ! test_have_prereq PERL_TEST_HELPERS\n> > +then\n> > +       skip_all='skipping ignores tests; Perl not available'\n> > +       test_done\n> > +fi\n> > diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\n> > @@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n> > +if ! test_have_prereq PERL_TEST_HELPERS\n> > +then\n> > +       skip_all='skipping ignores tests; Perl not available'\n> > +       test_done\n> > +fi\n> \n> This message seems to have been copy/pasted. Should it be instead\n> \"skipping apply-binary tests; Perl not available\"?\n\nYup, good catch!\n\nPatrick\n"},{"id":"514921","messageId":"Z-FUHrbyv8B1_Twp@pks.im","threadId":"63168","inReplyTo":"CAPig+cTE1K6bt-4v9sv9ywF7wwc5Od8s5scnLsvYPFGBU5HDHg@mail.gmail.com","subject":"Re: [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-24T12:46:22Z","receivedAt":"2025-03-24T12:46:25Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Mar 20, 2025 at 03:41:11PM -0400, Eric Sunshine wrote:\n> On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > The `name_from_description()` test helper uses Perl to munge a given\n> > description and convert it into a name. Refactor it to instead use a\n> > combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\n> > prerequisites in users of this library.\n> >\n> > Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> > ---\n> > diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\n> > @@ -109,13 +109,12 @@ check_output () {\n> >  # All alphanums translated into -'s which are then compressed and stripped\n> >  # from front and back.\n> >  name_from_description () {\n> > -       perl -pe '\n> > -               s/[^A-Za-z0-9.]/-/g;\n> > -               s/-+/-/g;\n> > -               s/-$//;\n> > -               s/^-//;\n> > -               y/A-Z/a-z/;\n> > -       '\n> > +       sed \\\n> > +               -e 's/[^A-Za-z0-9.]/-/g' \\\n> > +               -e 's/--*/-/g' \\\n> > +               -e 's/-$//' \\\n> > +               -e 's/^-//' |\n> > +       tr 'A-Z' 'a-z'\n> >  }\n> \n> Can't you just use sed's `y//` function directly instead of having to\n> separately invoke a `tr` command?\n\nAh, of course, will change!\n\nPatrick\n"},{"id":"514922","messageId":"Z-FUNgmY9hTsnzds@pks.im","threadId":"63168","inReplyTo":"CAPig+cSC3zdur1fCsa7RMNZDcgUK4pUGKb22tpgdANxR6OxNMA@mail.gmail.com","subject":"Re: [PATCH 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-24T12:46:46Z","receivedAt":"2025-03-24T12:46:50Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Mar 20, 2025 at 03:33:44PM -0400, Eric Sunshine wrote:\n> On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > A bunch of tests rely on Perl to print data in various different ways.\n> > These usages fall into the following categories:\n> >\n> >   - Print data conditionally by matching patterns. These usecases can be\n> >     converted to use awk(1) rather easily.\n> >\n> >   - Print data repeatedly. These usecases can typically be converted to\n> >     use a combination of `test-tool genzeros` and sed(1).\n> >\n> >   - Print data in reverse. These usecases can be converted to use\n> >     awk(1).\n> >\n> > Refactor the tests accordingly so that we can drop a couple of\n> > PERL_TEST_HELPERS prerequisites.\n> >\n> > Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> > ---\n> > diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\n> > @@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n> > -test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n> > +test_expect_success 'basic: can write large commit message' '\n> >         test_when_finished \"rm -rf repo\" &&\n> >         git init repo &&\n> > -       perl -e \"\n> > -               print \\\"this is a long commit message\\\" x 50000\n> > -       \" >commit-msg &&\n> > +\n> > +       awk \"BEGIN { for (i = 0; i < 50000; i++) print \\\"this is a long commit message\\\" }\" >commit-msg &&\n> >         git -C repo commit --allow-empty --file=../commit-msg\n> >  '\n> \n> The original Perl version emitted the entire message as a single-line,\n> whereas the awk replacement emits 50,000 lines. Was the intent of the\n> original specifically to check whether it handled an extremely long\n> line correctly, or was it merely checking whether an overall very\n> lengthy content was handled correctly? If the former, then this\n> semantic change is inconsistent with what this test wants to be\n> checking; if the latter, then this semantic change is harmless.\n\nIt really only wants to check for a big message, the exact format does\nnot matter at all. So in theory, we could even adapt this to use\n`test-tool genzeros | tr \"\\000\" \"a\"` or something like that, but I\ndidn't want to argue why that change is okay. The fact that we now have\na newline was unintentional.\n\n> Also, it is possible to do this entirely in shell without running an\n> external program (assuming `test` and `printf` are builtins):\n> \n>   i=0 &&\n>   while test $i -lt 50000\n>   do\n>     echo \"this is a long commit message\" &&\n>     i=$(($i+1)) ||\n>     return 1\n>   done &&\n\nTrue, but it's significantly slower. We already use awk in many places,\nso we can just as well use it here. I'll adapt the refactoring to drop\nthe newlines.\n\nPatrick\n"},{"id":"514956","messageId":"CAPig+cSN5hU=XP1Gd8z=5XyvSEqJcTBiWhgyJxYNBPJWAi3yLw@mail.gmail.com","threadId":"63168","inReplyTo":"Z-FUEhraLaDODbmO@pks.im","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-03-24T16:07:52Z","receivedAt":"2025-03-24T16:08:06Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 24, 2025 at 8:46 AM Patrick Steinhardt <ps@pks.im> wrote:\n> On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:\n> > On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> > > +test_expect_success 'rewrite diff respects textconv' '\n> > >         git diff -B >diff &&\n> > > -       grep \"dissimilarity index\" diff &&\n> > > -       grep \"^-61\" diff &&\n> > > -       grep \"^-0\" diff\n> > > +       test_grep \"dissimilarity index\" diff &&\n> > > +       test_grep \"^-3d 0a 00\" diff &&\n> > > +       test_grep \"^+3d 0a 01\" diff\n> > >  '\n> >\n> > This change seems unrelated to the stated purpose (`textconv`) of this patch(?).\n>\n> Not quite. The test previously didn't run because it depends on the\n> Perl-based textconv script. Now that this textconv script was adapted\n> to use shell scripting instead it can run, but as explained in the\n> commit message the output of the textconv script changed. We don't\n> really care for the exact output at all, we only care that textconv did\n> its thing. But we do have to adapt the test accordingly.\n\nOkay, I see that now that I have read your response and examined the\nchange more closely. The unrelated `grep` to `test_grep` change\nvisually overwhelms the diff, so much so that I overlooked the other\nsmaller necessary changes. Perhaps it would make sense to mention the\nunrelated change in the commit message but is not itself worth a\nreroll.\n"},{"id":"514957","messageId":"9fc64d33-43d0-4f7d-8630-fb9030065047@gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-11-b1eefe27ac55@pks.im","subject":"Re: [PATCH 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-03-24T16:16:17Z","receivedAt":"2025-03-24T16:16:20Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Patrick\n\nOn 20/03/2025 09:35, Patrick Steinhardt wrote:\n> We have a bunch of tests that use Perl to perform substitution via the\n> \"s/\" operator. These usecases can be trivially replaced with sed(1).\n> \n> Refactor the tests accordingly so that we can drop a couple of\n> PERL_TEST_HELPERS prerequisites.\n\nNice\n\n>   broken_c_unquote () {\n> -\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n> +\t<\"$1\" sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' | tr '\\n' '\\0'\n>   }\n>   \n>   broken_c_unquote_verbose () {\n> -\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n> +\t<\"$1\" sed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' | tr ':\\t\\n' '\\000'\n\nI found the redirection here rather strange - we can just do 'sed -e ... \n\"$1\" | tr ...'. The same applies to all the other sed commands that have \ntheir stdin redirected from a file.\n\nBest Wishes\n\nPhillip\n\n>   }\n>   \n>   stderr_contains () {\n> diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\n> index a92a42990b1..db75998e35f 100755\n> --- a/t/t4029-diff-trailing-space.sh\n> +++ b/t/t4029-diff-trailing-space.sh\n> @@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n>   EOF\n>   exit 1\n>   \n> -test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n> +test_expect_success \"$test_description\" '\n>   \tprintf \"\\nx\\n\" > f &&\n>   \tbefore=$(git hash-object f) &&\n>   \tbefore=$(git rev-parse --short $before) &&\n> @@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n>   \tgit config --bool diff.suppressBlankEmpty true &&\n>   \tgit diff f > actual &&\n>   \ttest_cmp exp actual &&\n> -\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n> +\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n> +\tmv exp.munged exp &&\n>   \tgit config --bool diff.suppressBlankEmpty false &&\n>   \tgit diff f > actual &&\n>   \ttest_cmp exp actual &&\n> diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\n> index 7fcca9ddad5..bacb93d014f 100755\n> --- a/t/t4200-rerere.sh\n> +++ b/t/t4200-rerere.sh\n> @@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping rerere tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   test_expect_success 'setup' '\n>   \tcat >a1 <<-\\EOF &&\n>   \tSome title\n> @@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n>   \ttest_might_fail git config --unset rerere.enabled &&\n>   \ttest_must_fail git merge first &&\n>   \n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1 &&\n>   \tgrep \"^=======\\$\" $rr/preimage &&\n>   \t! test -f $rr/postimage &&\n> @@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n>   \tgit reset --hard &&\n>   \ttest_must_fail git merge first &&\n>   \n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1 &&\n>   \tgrep ^=======$ $rr/preimage\n>   '\n> @@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n>   \tgit config rerere.enabled true &&\n>   \tgit reset --hard &&\n>   \ttest_must_fail git merge first &&\n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1\n>   '\n>   \n> diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\n> index ac5e370e1e4..07382797bbb 100755\n> --- a/t/t5303-pack-corruption-resilience.sh\n> +++ b/t/t5303-pack-corruption-resilience.sh\n> @@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n>   \tgit cat-file blob $blob_3 > /dev/null\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n> +test_expect_success 'create corruption in data of first object' '\n>   \tcreate_new_pack &&\n>   \tgit prune-packed &&\n>   \tchmod +w ${pack}.pack &&\n> -\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n> +\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n> +\tmv ${pack}.pack.munged ${pack}.pack &&\n>   \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n> @@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n>   \tgit cat-file blob $blob_3 > /dev/null\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n> +test_expect_success 'create corruption in data of first delta' '\n>   \tcreate_new_pack &&\n>   \tgit prune-packed &&\n>   \tchmod +w ${pack}.pack &&\n> -\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n> +\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n> +\tmv ${pack}.pack.munged ${pack}.pack &&\n>   \tgit cat-file blob $blob_1 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n> diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\n> index 81987296235..9033d72b8c7 100755\n> --- a/t/t5310-pack-bitmaps.sh\n> +++ b/t/t5310-pack-bitmaps.sh\n> @@ -395,7 +395,7 @@ test_bitmap_cases () {\n>   \t\t)\n>   \t'\n>   \n> -\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n> +\ttest_expect_success 'pack.preferBitmapTips' '\n>   \t\tgit init repo &&\n>   \t\ttest_when_finished \"rm -fr repo\" &&\n>   \t\t(\n> @@ -421,7 +421,7 @@ test_bitmap_cases () {\n>   \n>   \t\t\t# mark the commits which did not receive bitmaps as preferred,\n>   \t\t\t# and generate the bitmap again\n> -\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n> +\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n>   \t\t\t\tgit update-ref --stdin &&\n>   \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n>   \n> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\n> index 342d0423c92..d5c0d00114e 100755\n> --- a/t/t5534-push-signed.sh\n> +++ b/t/t5534-push-signed.sh\n> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n>   \ttest_cmp expect dst/push-cert-status\n>   '\n>   \n> -test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n> +test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n>   \t# First, invoke receive-pack with dummy input to obtain its preamble.\n>   \tprepare_dst &&\n>   \tgit -C dst config receive.certnonceseed sekrit &&\n> @@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n>   \t# Tweak the push output to make the push option outside the cert\n>   \t# different, then replay it on a fresh dst, checking that ff is not\n>   \t# deleted.\n> -\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n> +\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n>   \tprepare_dst &&\n>   \tgit -C dst config receive.certnonceseed sekrit &&\n>   \tgit -C dst config receive.advertisepushoptions 1 &&\n> diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\n> index 6131c361094..12329aab388 100755\n> --- a/t/t6011-rev-list-with-bad-commit.sh\n> +++ b/t/t6011-rev-list-with-bad-commit.sh\n> @@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   # Note:\n>   # - compression level is set to zero to make \"corruptions\" easier to perform\n>   # - reflog is disabled to avoid extra references which would twart the test\n> @@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n>      first_commit=$(git rev-parse HEAD~3)\n>      '\n>   \n> -test_expect_success 'corrupt second commit object' \\\n> -   '\n> -   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n> -   test_must_fail git fsck --full\n> -   '\n> +test_expect_success 'corrupt second commit object' '\n> +\tfor p in .git/objects/pack/*.pack\n> +\tdo\n> +\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n> +\t\tmv \"$p.munged\" \"$p\" ||\n> +\t\treturn 1\n> +\tdone &&\n> +\ttest_must_fail git fsck --full\n> +'\n>   \n>   test_expect_success 'rev-list should fail' '\n>   \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\n> diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\n> index 14069600a2f..00b81d349b9 100755\n> --- a/t/t7416-submodule-dash-url.sh\n> +++ b/t/t7416-submodule-dash-url.sh\n> @@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping submodule dash URL tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   test_expect_success 'setup' '\n>   \tgit config --global protocol.file.allow always\n>   '\n> @@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n>   '\n>   \n>   test_expect_success 'remove ./ protection from .gitmodules url' '\n> -\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n> +\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n> +\tmv .gitmodules.munged .gitmodules &&\n>   \tgit commit -am \"drop protection\"\n>   '\n>   \n> diff --git a/t/t7508-status.sh b/t/t7508-status.sh\n> index 14c41b2cb7c..cdc1d6fcc78 100755\n> --- a/t/t7508-status.sh\n> +++ b/t/t7508-status.sh\n> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n>   \ttest_cmp expect output\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n> +test_expect_success 'status -z implies porcelain' '\n>   \tgit status --porcelain |\n> -\tperl -pe \"s/\\012/\\000/g\" >expect &&\n> +\ttr \"\\012\" \"\\000\" >expect &&\n>   \tgit status -z >output &&\n>   \ttest_cmp expect output\n>   '\n> diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\n> index 5cb16872081..810dac18f56 100755\n> --- a/t/t8006-blame-textconv.sh\n> +++ b/t/t8006-blame-textconv.sh\n> @@ -4,12 +4,6 @@ test_description='git blame textconv support'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping blame textconv tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   find_blame() {\n>   \tsed -e 's/^[^(]*//'\n>   }\n> @@ -17,7 +11,7 @@ find_blame() {\n>   cat >helper <<'EOF'\n>   #!/bin/sh\n>   grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n> -\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n> +sed 's/^bin: /converted: /' <\"$1\"\n>   EOF\n>   chmod +x helper\n>   \n> diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\n> index a9d38be997c..9afdb45b1cc 100755\n> --- a/t/t9137-git-svn-dcommit-clobber-series.sh\n> +++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n> @@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n>   \ttest -e file\n>   \t'\n>   \n> -test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n> +test_expect_success '(supposedly) non-conflicting change from SVN' '\n>   \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n>   \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n>   \tsvn_cmd co \"$svnrepo\" tmp &&\n>   \t(cd tmp &&\n> -\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n> -\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n> +\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n> +\t\tmv file.munged file &&\n>   \t\tpoke file &&\n>   \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n>   \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n> @@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n>   \tgit commit -m bye-life life\n>   \t\"\n>   \n> -test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n> +test_expect_success 'change file but in unrelated area' \"\n>   \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n>   \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n> -\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n> -\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n> +\tsed -e 's/^4\\$/4444/' \\\n> +\t    -e 's/^7\\$/7777/' \\\n> +\t\t<file >file.munged &&\n> +\tmv file.munged file &&\n>   \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n>   \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n>   \tgit commit -m '4 => 4444, 7 => 7777' file &&\n> \n\n"},{"id":"514958","messageId":"80c2e84e-6603-4e96-8934-8219c55d4d36@gmail.com","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-13-b1eefe27ac55@pks.im","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-03-24T16:16:22Z","receivedAt":"2025-03-24T16:16:24Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Patrick\n\nOn 20/03/2025 09:35, Patrick Steinhardt wrote:\n> We have a couple of tests that depend on Perl for textconv scripts.\n> Refactor these tests to instead be implemented via shell utilities so\n> that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n> \n> Note that not all of the conversions are a one-to-one equivalent to the\n> previous textconv scripts. But that's not really needed in the first\n> place: we only care that the textconv script does something, and that\n> can be verified trivially without having a full-blown invocation of\n> hexdump. So at times, the implementation of the textconv scripts is\n> reduced to their bare minimum.\n > > -cat >hexdump <<'EOF'\n> -#!/bin/sh\n> -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> -EOF\n> -chmod +x hexdump\n> -\n>   test_expect_success 'setup binary file with history' '\n> +\twrite_script hexdump <<-\\EOF &&\n> +\ttr \"\\000\\001\" \"01\" <\"$1\"\nI guess it is fine just to handle the characters we expect at the moment \n(is that what the second paragraph of the commit message is referring \nto?), but the script it was more tolerant of future changes to the test \ndata. We could always just use 'test-tool hexdump' here like the tests \nbelow but it is probably not worth a re-roll on its own.\n\nOverall this series looks like a useful improvement.\n\nThanks\n\nPhillip\n\n> +\tEOF\n>   \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n>   \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n>   '\n> diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\n> index cbe50b15772..15e012ccc7c 100755\n> --- a/t/t4031-diff-rewrite-binary.sh\n> +++ b/t/t4031-diff-rewrite-binary.sh\n> @@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n>   \tgrep \" rewrite file\" diff\n>   '\n>   \n> -{\n> -\techo \"#!$SHELL_PATH\"\n> -\tcat <<'EOF'\n> -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> -EOF\n> -} >dump\n> -chmod +x dump\n> -\n>   test_expect_success 'setup textconv' '\n> +\twrite_script dump <<-\\EOF &&\n> +\ttest-tool hexdump <\"$1\"\n> +\tEOF\n>   \techo file diff=foo >.gitattributes &&\n>   \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> +test_expect_success 'rewrite diff respects textconv' '\n>   \tgit diff -B >diff &&\n> -\tgrep \"dissimilarity index\" diff &&\n> -\tgrep \"^-61\" diff &&\n> -\tgrep \"^-0\" diff\n> +\ttest_grep \"dissimilarity index\" diff &&\n> +\ttest_grep \"^-3d 0a 00\" diff &&\n> +\ttest_grep \"^+3d 0a 01\" diff\n>   '\n>   \n>   test_done\n> diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\n> index b2730d200c8..3bd91da9707 100755\n> --- a/t/t7815-grep-binary.sh\n> +++ b/t/t7815-grep-binary.sh\n> @@ -4,12 +4,6 @@ test_description='git grep in binary files'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping grep binary tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   test_expect_success 'setup' \"\n>   \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n>   \tgit add a &&\n> @@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n>   \ttest_cmp expect actual\n>   '\n>   \n> -cat >nul_to_q_textconv <<'EOF'\n> -#!/bin/sh\n> -\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n> -EOF\n> -chmod +x nul_to_q_textconv\n> -\n>   test_expect_success 'setup textconv filters' '\n> +\twrite_script nul_to_q_textconv <<-\\EOF &&\n> +\ttr \"\\000\" \"Q\" <\"$1\"\n> +\tEOF\n>   \techo a diff=foo >.gitattributes &&\n>   \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n>   '\n> \n\n"},{"id":"514996","messageId":"Z-KkxRcgTtLRd2W-@pks.im","threadId":"63168","inReplyTo":"CAPig+cSN5hU=XP1Gd8z=5XyvSEqJcTBiWhgyJxYNBPJWAi3yLw@mail.gmail.com","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T12:42:45Z","receivedAt":"2025-03-25T12:42:53Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Mar 24, 2025 at 12:07:52PM -0400, Eric Sunshine wrote:\n> On Mon, Mar 24, 2025 at 8:46 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:\n> > > On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > > > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> > > > +test_expect_success 'rewrite diff respects textconv' '\n> > > >         git diff -B >diff &&\n> > > > -       grep \"dissimilarity index\" diff &&\n> > > > -       grep \"^-61\" diff &&\n> > > > -       grep \"^-0\" diff\n> > > > +       test_grep \"dissimilarity index\" diff &&\n> > > > +       test_grep \"^-3d 0a 00\" diff &&\n> > > > +       test_grep \"^+3d 0a 01\" diff\n> > > >  '\n> > >\n> > > This change seems unrelated to the stated purpose (`textconv`) of this patch(?).\n> >\n> > Not quite. The test previously didn't run because it depends on the\n> > Perl-based textconv script. Now that this textconv script was adapted\n> > to use shell scripting instead it can run, but as explained in the\n> > commit message the output of the textconv script changed. We don't\n> > really care for the exact output at all, we only care that textconv did\n> > its thing. But we do have to adapt the test accordingly.\n> \n> Okay, I see that now that I have read your response and examined the\n> change more closely. The unrelated `grep` to `test_grep` change\n> visually overwhelms the diff, so much so that I overlooked the other\n> smaller necessary changes. Perhaps it would make sense to mention the\n> unrelated change in the commit message but is not itself worth a\n> reroll.\n\nI already tried to describe this in the commit message, but obviously I\nseem to have failed :) I'll add another sentence to mention that tests\nhave to be adapted accordingly.\n\nPatrick\n"},{"id":"514997","messageId":"Z-Kk8c4INZilK8jM@pks.im","threadId":"63168","inReplyTo":"80c2e84e-6603-4e96-8934-8219c55d4d36@gmail.com","subject":"Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T12:43:29Z","receivedAt":"2025-03-25T12:43:33Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Mar 24, 2025 at 04:16:22PM +0000, Phillip Wood wrote:\n> Hi Patrick\n> \n> On 20/03/2025 09:35, Patrick Steinhardt wrote:\n> > We have a couple of tests that depend on Perl for textconv scripts.\n> > Refactor these tests to instead be implemented via shell utilities so\n> > that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n> > \n> > Note that not all of the conversions are a one-to-one equivalent to the\n> > previous textconv scripts. But that's not really needed in the first\n> > place: we only care that the textconv script does something, and that\n> > can be verified trivially without having a full-blown invocation of\n> > hexdump. So at times, the implementation of the textconv scripts is\n> > reduced to their bare minimum.\n> > > -cat >hexdump <<'EOF'\n> > -#!/bin/sh\n> > -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> > -EOF\n> > -chmod +x hexdump\n> > -\n> >   test_expect_success 'setup binary file with history' '\n> > +\twrite_script hexdump <<-\\EOF &&\n> > +\ttr \"\\000\\001\" \"01\" <\"$1\"\n> I guess it is fine just to handle the characters we expect at the moment (is\n> that what the second paragraph of the commit message is referring to?), but\n> the script it was more tolerant of future changes to the test data. We could\n> always just use 'test-tool hexdump' here like the tests below but it is\n> probably not worth a re-roll on its own.\n\nThat was my first version, but it required a bunch of changes to tests\nall over the place. So I decided to simplify this test suite to do the\nbare minimum.\n\nPatrick\n"},{"id":"514999","messageId":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH v2 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:18Z","receivedAt":"2025-03-25T13:14:24Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nwhile Git was initially building on Perl quite a lot, the significance\nof Perl has been dwindling over the years as more and more functionality\nwas converted into C builtins. Nowadays, an installation with Perl-based\nfeatures disabled is almost fully functional, only a handful of features\nremain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these features really are critical for day-to-day usage of Git,\nand most users probably wouldn't even notice if those features were not\ninstalled. Perl is thus very much optional nowadays.\n\nThere is one big exception though: it is impossible to run our test\nsuite without a Perl interpreter, so it is not easily possible to verify\nthat a Perl-less installation actually works as expected. For most of\nthe part though our test suite doesn't use all that much Perl, either.\nIt is present in a couple of critical paths, but those are easy to adapt\nto not use Perl anymore.\n\nThis is exactly what this patch series does: it refactors a couple of\ncentral parts in our test suite to not use Perl anymore so that it\nbecomes possible to run most of our tests entirely without Perl. Tests\nthat still depend on Perl are marked with a new PERL_TEST_HELPERS prereq\nso that they only execute when a Perl interpreter is available.\n\nWith this patch series, 30342 out of 31358 tests pass, which is around\n97% of our tests.\n\nChanges in v2:\n  - Improve a couple of conversions based on feedback.\n  - Clarify the commit message of the textconv conversion.\n  - Fix a copy-paste error when it comes to skipping tests in t4103.\n  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (20):\n      t: skip chain lint when PERL_PATH is unset\n      t: refactor environment sanitization to not use Perl\n      t: adapt character translation helpers to not use Perl\n      t: adapt `test_copy_bytes()` to not use Perl\n      t: adapt `test_readlink()` to not use Perl\n      t: introduce PERL_TEST_HELPERS prerequisite\n      t: adapt existing PERL prerequisites\n      meson: stop requiring Perl when tests are enabled\n      Makefile: stop requiring Perl when running tests\n      t: refactor tests depending on Perl transliteration operator\n      t: refactor tests depending on Perl substitution operator\n      t: refactor tests depending on Perl to print data\n      t: refactor tests depending on Perl for textconv scripts\n      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n      t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n      t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n      t0021: refactor `generate_random_characters()` to not depend on Perl\n      t0210: refactor trace2 scrubbing to not use Perl\n      t5316: refactor `max_chain()` to not depend on Perl\n      t5703: refactor test to not depend on Perl\n\n meson.build                               |  2 +-\n t/Makefile                                | 16 +++++++--\n t/helper/test-path-utils.c                | 13 ++++++++\n t/helper/test-sha1.sh                     |  4 +--\n t/lib-diff.sh                             |  4 +--\n t/lib-gpg.sh                              |  6 +---\n t/lib-httpd.sh                            |  2 +-\n t/lib-httpd/apache.conf                   |  6 ++--\n t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------\n t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++\n t/lib-t6000.sh                            | 13 ++++----\n t/t0008-ignores.sh                        |  4 +--\n t/t0021-conversion.sh                     | 13 ++++----\n t/t0090-cache-tree.sh                     |  4 +--\n t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------\n t/t0210/scrub_normal.perl                 | 54 ------------------------------\n t/t0211-trace2-perf.sh                    |  6 ++++\n t/t0610-reftable-basics.sh                |  5 ++-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       | 16 +++++----\n t/t1007-hash-object.sh                    |  6 ++--\n t/t1010-mktree.sh                         |  4 +--\n t/t1450-fsck.sh                           |  6 ++--\n t/t3300-funny-names.sh                    |  6 ++--\n t/t4013-diff-various.sh                   |  6 ++++\n t/t4014-format-patch.sh                   | 30 ++++++++---------\n t/t4020-diff-external.sh                  |  2 +-\n t/t4029-diff-trailing-space.sh            |  3 +-\n t/t4030-diff-textconv.sh                  |  9 ++---\n t/t4031-diff-rewrite-binary.sh            | 17 ++++------\n t/t4058-diff-duplicates.sh                |  6 ++++\n t/t4103-apply-binary.sh                   |  6 ++--\n t/t4116-apply-reverse.sh                  |  4 +--\n t/t4150-am.sh                             |  8 ++---\n t/t4200-rerere.sh                         |  8 ++---\n t/t4205-log-pretty-formats.sh             |  6 ++--\n t/t4216-log-bloom.sh                      |  8 ++---\n t/t5004-archive-corner-cases.sh           |  6 ++++\n t/t5300-pack-object.sh                    | 10 +++---\n t/t5303-pack-corruption-resilience.sh     |  6 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               | 10 +++---\n t/t5318-commit-graph.sh                   | 12 +++----\n t/t5319-multi-pack-index.sh               | 16 ++++-----\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  4 +--\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  2 +-\n t/t5503-tagfollow.sh                      |  6 ++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++\n t/t5532-fetch-proxy.sh                    |  6 ++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  | 15 ++++-----\n t/t5551-http-fetch-smart.sh               |  7 ++++\n t/t5562-http-backend-content-length.sh    |  6 ++++\n t/t5601-clone.sh                          |  4 +--\n t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------\n t/t5701-git-serve.sh                      |  5 ++-\n t/t5702-protocol-v2.sh                    | 21 +++++++-----\n t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------\n t/t5710-promisor-remote-capability.sh     |  6 ++++\n t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---\n t/t6013-rev-list-reverse-parents.sh       | 10 +++---\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++\n t/t6115-rev-list-du.sh                    |  2 +-\n t/t6300-for-each-ref.sh                   | 15 ++++++---\n t/t7006-pager.sh                          |  6 ++--\n t/t7416-submodule-dash-url.sh             |  3 +-\n t/t7501-commit-basic-functionality.sh     |  6 ++--\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  9 ++---\n t/t8001-annotate.sh                       |  6 ++++\n t/t8002-blame.sh                          |  8 ++++-\n t/t8006-blame-textconv.sh                 |  2 +-\n t/t8011-blame-split-file.sh               |  6 ++--\n t/t8012-blame-colors.sh                   |  6 ++++\n t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib-functions.sh                   | 20 +++--------\n t/test-lib.sh                             | 49 +++++++++++++++++----------\n 84 files changed, 471 insertions(+), 373 deletions(-)\n\nRange-diff versus v1:\n\n 1:  83596f2aa05 !  1:  658a45496a3 t: skip chain lint when PERL_PATH is unset\n    @@ Metadata\n      ## Commit message ##\n         t: skip chain lint when PERL_PATH is unset\n     \n    -    Our chainlint scripts verify that test files have proper '&&' chains.\n    -    These scripts are written in Perl and are executed for every test file\n    -    before executing the test logic itself.\n    +    Our chainlint script verifies that test files have proper '&&' chains.\n    +    This script is written in Perl and executed for every test file before\n    +    executing the test logic itself.\n     \n         In subsequent commits we're about to refactor our test suite so that\n         Perl becomes an optional dependency, only. And while it is already\n 2:  67e9859721d =  2:  12a618f141a t: refactor environment sanitization to not use Perl\n 3:  6ebfa6a8581 =  3:  37b5ee501c7 t: adapt character translation helpers to not use Perl\n 4:  01e9fce3751 =  4:  df0e1185b3b t: adapt `test_copy_bytes()` to not use Perl\n 5:  1f291160713 =  5:  badfad15e0c t: adapt `test_readlink()` to not use Perl\n 6:  ab15650ca76 !  6:  ae30c6a1524 t: introduce PERL_TEST_HELPERS prerequisite\n    @@ t/t4103-apply-binary.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n      \n     +if ! test_have_prereq PERL_TEST_HELPERS\n     +then\n    -+\tskip_all='skipping ignores tests; Perl not available'\n    ++\tskip_all='skipping apply-binary tests; Perl not available'\n     +\ttest_done\n     +fi\n     +\n 7:  d278b3c6d90 =  7:  8084db771c1 t: adapt existing PERL prerequisites\n 8:  bb8b13b2669 =  8:  87b58043c59 meson: stop requiring Perl when tests are enabled\n 9:  6b2a77c2dc4 =  9:  b9831e97fca Makefile: stop requiring Perl when running tests\n10:  0af780a491b ! 10:  4b3a4f5a1e5 t: refactor tests depending on Perl transliteration operator\n    @@ t/t4103-apply-binary.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n      \n     -if ! test_have_prereq PERL_TEST_HELPERS\n     -then\n    --\tskip_all='skipping ignores tests; Perl not available'\n    +-\tskip_all='skipping apply-binary tests; Perl not available'\n     -\ttest_done\n     -fi\n     -\n11:  c57d1a1dc14 ! 11:  20ccdb34dc8 t: refactor tests depending on Perl substitution operator\n    @@ t/t0008-ignores.sh: test_stderr () {\n      \n      broken_c_unquote () {\n     -\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n    -+\t<\"$1\" sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' | tr '\\n' '\\0'\n    ++\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n      }\n      \n      broken_c_unquote_verbose () {\n     -\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n    -+\t<\"$1\" sed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' | tr ':\\t\\n' '\\000'\n    ++\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n      }\n      \n      stderr_contains () {\n12:  4cf1615b49a ! 12:  a6c15a4b619 t: refactor tests depending on Perl to print data\n    @@ t/t0610-reftable-basics.sh: test_expect_success 'basic: commit and list refs' '\n     -\t\tprint \\\"this is a long commit message\\\" x 50000\n     -\t\" >commit-msg &&\n     +\n    -+\tawk \"BEGIN { for (i = 0; i < 50000; i++) print \\\"this is a long commit message\\\" }\" >commit-msg &&\n    ++\tawk \"BEGIN { for (i = 0; i < 50000; i++) printf \\\"%s\\\", \\\"this is a long commit message\\\" }\" >commit-msg &&\n      \tgit -C repo commit --allow-empty --file=../commit-msg\n      '\n      \n13:  de36109ff9f ! 13:  4e6c4c88d4c t: refactor tests depending on Perl for textconv scripts\n    @@ Commit message\n         place: we only care that the textconv script does something, and that\n         can be verified trivially without having a full-blown invocation of\n         hexdump. So at times, the implementation of the textconv scripts is\n    -    reduced to their bare minimum.\n    +    reduced to their bare minimum and the expectations of those tests are\n    +    adapted accordingly.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n14:  ac0537394ab = 14:  28d6a862403 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n15:  96486f46150 ! 15:  17fbc84e23c t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n    @@ t/lib-t6000.sh: check_output () {\n     +\t\t-e 's/[^A-Za-z0-9.]/-/g' \\\n     +\t\t-e 's/--*/-/g' \\\n     +\t\t-e 's/-$//' \\\n    -+\t\t-e 's/^-//' |\n    -+\ttr 'A-Z' 'a-z'\n    ++\t\t-e 's/^-//' \\\n    ++\t\t-e 'y/A-Z/a-z/'\n      }\n      \n      \n16:  2b418ae8d8f = 16:  de58d23e7ab t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n17:  8eb9b127db6 = 17:  517094e41a6 t0021: refactor `generate_random_characters()` to not depend on Perl\n18:  8d0e583f741 = 18:  0eecfc633bd t0210: refactor trace2 scrubbing to not use Perl\n19:  7c5dc0d66b1 = 19:  8a2b080c949 t5316: refactor `max_chain()` to not depend on Perl\n20:  8a35ab947b5 = 20:  118b00003ea t5703: refactor test to not depend on Perl\n\n---\nbase-commit: 683c54c999c301c2cd6f715c411407c413b1d84e\nchange-id: 20250317-b4-pks-t-perlless-138cf94696b8\n\n"},{"id":"515000","messageId":"20250325-b4-pks-t-perlless-v2-1-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:19Z","receivedAt":"2025-03-25T13:14:26Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our chainlint script verifies that test files have proper '&&' chains.\nThis script is written in Perl and executed for every test file before\nexecuting the test logic itself.\n\nIn subsequent commits we're about to refactor our test suite so that\nPerl becomes an optional dependency, only. And while it is already\npossible to disable this linter, developers that don't have Perl\navailable at all would always have to disable the linter manually, which\nis rather cumbersome.\n\nDisable the chain linter automatically in case PERL_PATH isn't set to\nmake this a bit less annoying. Bail out with an error in case the\ndeveloper has asked explicitly for the chain linter.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..1ce3b32fcac 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1523,6 +1523,22 @@ then\n \texport LSAN_OPTIONS\n fi\n \n+if test -z \"$PERL_PATH\"\n+then\n+\tcase \"${GIT_TEST_CHAIN_LINT:-unset}\" in\n+\tunset)\n+\t\tGIT_TEST_CHAIN_LINT=0\n+\t\t;;\n+\t0)\n+\t\t# The user has explicitly disabled the chain linter, so we\n+\t\t# don't have anything to worry about.\n+\t\t;;\n+\t*)\n+\t\tBAIL_OUT 'You need Perl for the chain linter'\n+\t\t;;\n+\tesac\n+fi\n+\n if test \"${GIT_TEST_CHAIN_LINT:-1}\" != 0 &&\n    test \"${GIT_TEST_EXT_CHAIN_LINT:-1}\" != 0\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515001","messageId":"20250325-b4-pks-t-perlless-v2-2-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 02/20] t: refactor environment sanitization to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:20Z","receivedAt":"2025-03-25T13:14:27Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Before executing tests we first sanitize the environment. Part of the\nsanitization is to unset a couple of environment variables that we know\nwill change the behaviour of Git. This is done with a small Perl script,\nwhich has the consequence that having a Perl interpreter available is a\nstrict requirement for running our unit tests.\n\nThe logic itself isn't particularly involved: we simply unset every\nenvironment variable whose key starts with 'GIT_', but then explicitly\nallow a subset of these.\n\nRefactor the logic to instead use sed(1) so that it becomes possible to\nexecute our tests without Perl.\n\nBased-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 32 ++++++++++++++------------------\n 1 file changed, 14 insertions(+), 18 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 1ce3b32fcac..a62699d6c79 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -499,24 +499,20 @@ EDITOR=:\n # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets\n # deriving from the command substitution clustered with the other\n # ones.\n-unset VISUAL EMAIL LANGUAGE $(\"$PERL_PATH\" -e '\n-\tmy @env = keys %ENV;\n-\tmy $ok = join(\"|\", qw(\n-\t\tTRACE\n-\t\tDEBUG\n-\t\tTEST\n-\t\t.*_TEST\n-\t\tPROVE\n-\t\tVALGRIND\n-\t\tUNZIP\n-\t\tPERF_\n-\t\tCURL_VERBOSE\n-\t\tTRACE_CURL\n-\t\tBUILD_DIR\n-\t));\n-\tmy @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);\n-\tprint join(\"\\n\", @vars);\n-')\n+unset VISUAL EMAIL LANGUAGE $(env | sed -n \\\n+\t-e '/^GIT_TRACE/d' \\\n+\t-e '/^GIT_DEBUG/d' \\\n+\t-e '/^GIT_TEST/d' \\\n+\t-e '/^GIT_.*_TEST/d' \\\n+\t-e '/^GIT_PROVE/d' \\\n+\t-e '/^GIT_VALGRIND/d' \\\n+\t-e '/^GIT_UNZIP/d' \\\n+\t-e '/^GIT_PERF_/d' \\\n+\t-e '/^GIT_CURL_VERBOSE/d' \\\n+\t-e '/^GIT_TRACE_CURL/d' \\\n+\t-e '/^GIT_BUILD_DIR/d' \\\n+\t-e 's/^\\(GIT_[^=]*\\)=.*/\\1/p'\n+)\n unset XDG_CACHE_HOME\n unset XDG_CONFIG_HOME\n unset GITPERLLIB\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515002","messageId":"20250325-b4-pks-t-perlless-v2-3-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 03/20] t: adapt character translation helpers to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:21Z","receivedAt":"2025-03-25T13:14:28Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of helper functions that translate characters, e.g.\nfrom LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl\nscripts, but they can be trivially adapted to instead use tr(1).\n\nNote that one specialty here is the handling of NUL characters in tr(1),\nwhich historically wasn't implemented correctly on all platforms. But\nquoting tr(1p):\n\n    It was considered that automatically stripping NUL characters from\n    the input was not correct functionality.  However, the removal of -n\n    in a later proposal does not remove the requirement that tr\n    correctly process NUL characters in its input stream.\n\nSo when tr(1) is implemented following the POSIX standard then it is\nexpected to handle the transliteration of NUL just fine.\n\nRefactor the helpers accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 79377bc0fc2..377f08a1428 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -88,15 +88,15 @@ test_decode_color () {\n }\n \n lf_to_nul () {\n-\tperl -pe 'y/\\012/\\000/'\n+\ttr '\\012' '\\000'\n }\n \n nul_to_q () {\n-\tperl -pe 'y/\\000/Q/'\n+\ttr '\\000' 'Q'\n }\n \n q_to_nul () {\n-\tperl -pe 'y/Q/\\000/'\n+\ttr 'Q' '\\000'\n }\n \n q_to_cr () {\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515003","messageId":"20250325-b4-pks-t-perlless-v2-5-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 05/20] t: adapt `test_readlink()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:23Z","receivedAt":"2025-03-25T13:14:28Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_readlink()` helper function reads a symbolic link and returns\nthe path it is pointing to. It is thus equivalent to the readlink(1)\nutility, which isn't available on all supported platforms. As such, it\nis implemented using Perl so that we can use it even on platforms where\nthe shell utility isn't available.\n\nWhile using readlink(1) is not an option, what we can do is to implement\nthe logic ourselves in our test-tool. Do so, which allows a bunch of\ntests to pass when Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-path-utils.c | 13 +++++++++++++\n t/test-lib-functions.sh    |  2 +-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 72ac8d1b1b0..54d9ba98c0e 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc >= 2 && !strcmp(argv[1], \"readlink\")) {\n+\t\tstruct strbuf target = STRBUF_INIT;\n+\t\twhile (argc > 2) {\n+\t\t\tif (strbuf_readlink(&target, argv[2], 0) < 0)\n+\t\t\t\tdie_errno(\"cannot read link at '%s'\", argv[2]);\n+\t\t\tputs(target.buf);\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t}\n+\t\tstrbuf_release(&target);\n+\t\treturn 0;\n+\t}\n+\n \tif (argc >= 2 && !strcmp(argv[1], \"absolute_path\")) {\n \t\twhile (argc > 2) {\n \t\t\tputs(absolute_path(argv[2]));\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex c4b4d3a4c7f..bff8c4d1b41 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1979,7 +1979,7 @@ test_remote_https_urls() {\n # Print the destination of symlink(s) provided as arguments. Basically\n # the same as the readlink command, but it's not available everywhere.\n test_readlink () {\n-\tperl -le 'print readlink($_) for @ARGV' \"$@\"\n+\ttest-tool path-utils readlink \"$@\"\n }\n \n # Set mtime to a fixed \"magic\" timestamp in mid February 2009, before we\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515004","messageId":"20250325-b4-pks-t-perlless-v2-4-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 04/20] t: adapt `test_copy_bytes()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:22Z","receivedAt":"2025-03-25T13:14:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_copy_bytes()` helper function copies up to N bytes from stdin\nto stdout. This is implemented using Perl, but it can be trivially\nadapted to instead use dd(1).\n\nRefactor the helper accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 12 +-----------\n 1 file changed, 1 insertion(+), 11 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 377f08a1428..c4b4d3a4c7f 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1640,17 +1640,7 @@ test_match_signal () {\n \n # Read up to \"$1\" bytes (or to EOF) from stdin and write them to stdout.\n test_copy_bytes () {\n-\tperl -e '\n-\t\tmy $len = $ARGV[1];\n-\t\twhile ($len > 0) {\n-\t\t\tmy $s;\n-\t\t\tmy $nread = sysread(STDIN, $s, $len);\n-\t\t\tdie \"cannot read: $!\" unless defined($nread);\n-\t\t\tlast unless $nread;\n-\t\t\tprint $s;\n-\t\t\t$len -= $nread;\n-\t\t}\n-\t' - \"$1\"\n+\tdd ibs=1 count=\"$1\" 2>/dev/null\n }\n \n # run \"$@\" inside a non-git directory\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515007","messageId":"20250325-b4-pks-t-perlless-v2-6-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:24Z","receivedAt":"2025-03-25T13:14:30Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"In the early days of Git, Perl was used quite prominently throughout the\nproject. This has changed significantly as almost all of the executables\nwe ship nowadays have eventually been rewritten in C. Only a handful of\nsubsystems remain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these subsystems can really be considered to be part of the\n\"core\" of Git, and an installation without them is fully functional.\nIt is more likely than not that an end user wouldn't even notice that\nany features are missing if those tools weren't installed. But while\nPerl nowadays very much is an optional dependency of Git, there is a\nsignificant limitation when Perl isn't available: developers cannot run\nour test suite.\n\nPreceding commits have started to lift this restriction by removing the\nstrict dependency on Perl in many central parts of the test library. But\nthere are still many tests that rely on small Perl helpers to do various\ndifferent things.\n\nIntroduce a new PERL_TEST_HELPERS prerequisite that guards all tests\nthat require Perl. This prerequisite is explicitly different than the\npreexisting PERL prerequisite:\n\n  - PERL records whether or not features depending on the Perl\n    interpreter are built.\n\n  - PERL_TEST_HELPERS records whether or not a Perl interpreter is\n    available for our tests.\n\nBy having these two separate prerequisites we can thus distinguish\nbetween tests that inherently depend on Perl because the underlying\nfeature does, and those tests that depend on Perl because the test\nitself is using Perl.\n\nAdapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        |  6 ++++++\n t/t0021-conversion.sh                     |  4 ++--\n t/t0210-trace2-normal.sh                  |  6 ++++++\n t/t0211-trace2-perf.sh                    |  6 ++++++\n t/t0610-reftable-basics.sh                |  2 +-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       |  2 +-\n t/t1007-hash-object.sh                    |  6 +++---\n t/t1010-mktree.sh                         |  4 ++--\n t/t1450-fsck.sh                           |  6 +++---\n t/t3300-funny-names.sh                    |  6 +++---\n t/t4013-diff-various.sh                   |  6 ++++++\n t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------\n t/t4020-diff-external.sh                  |  4 ++--\n t/t4029-diff-trailing-space.sh            |  2 +-\n t/t4030-diff-textconv.sh                  |  6 ++++++\n t/t4031-diff-rewrite-binary.sh            |  2 +-\n t/t4058-diff-duplicates.sh                |  6 ++++++\n t/t4103-apply-binary.sh                   |  6 ++++++\n t/t4116-apply-reverse.sh                  |  6 ++++++\n t/t4150-am.sh                             |  2 +-\n t/t4200-rerere.sh                         |  6 ++++++\n t/t4205-log-pretty-formats.sh             |  6 +++---\n t/t4216-log-bloom.sh                      |  8 ++++----\n t/t5004-archive-corner-cases.sh           |  6 ++++++\n t/t5300-pack-object.sh                    |  6 ++++++\n t/t5303-pack-corruption-resilience.sh     |  4 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               |  8 ++++----\n t/t5318-commit-graph.sh                   | 12 ++++++------\n t/t5319-multi-pack-index.sh               | 16 ++++++++--------\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  2 +-\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  4 ++--\n t/t5503-tagfollow.sh                      |  6 ++++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++++\n t/t5532-fetch-proxy.sh                    |  6 ++++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  |  2 +-\n t/t5551-http-fetch-smart.sh               |  7 +++++++\n t/t5562-http-backend-content-length.sh    |  6 ++++++\n t/t5601-clone.sh                          |  4 ++--\n t/t5616-partial-clone.sh                  |  6 +++---\n t/t5701-git-serve.sh                      |  2 +-\n t/t5702-protocol-v2.sh                    |  6 +++---\n t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++\n t/t5710-promisor-remote-capability.sh     |  6 ++++++\n t/t6002-rev-list-bisect.sh                |  6 ++++++\n t/t6003-rev-list-topo-order.sh            |  6 ++++++\n t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++\n t/t6013-rev-list-reverse-parents.sh       |  4 ++--\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++\n t/t6115-rev-list-du.sh                    |  6 ++++++\n t/t6300-for-each-ref.sh                   |  6 ++++++\n t/t7006-pager.sh                          |  2 +-\n t/t7416-submodule-dash-url.sh             |  6 ++++++\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  6 ++++++\n t/t8001-annotate.sh                       |  6 ++++++\n t/t8002-blame.sh                          |  6 ++++++\n t/t8006-blame-textconv.sh                 |  6 ++++++\n t/t8011-blame-split-file.sh               |  6 +++---\n t/t8012-blame-colors.sh                   |  6 ++++++\n t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib.sh                             |  1 +\n 71 files changed, 281 insertions(+), 93 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c9376dffb58..1aaa6bf5ae8 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,6 +5,12 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping ignores tests; Perl not available'\n+\ttest_done\n+fi\n+\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 3f6433d3045..9c3738ebb3f 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success 'required process filter should process multiple packets' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '\n \t)\n '\n \n-test_expect_success 'required process filter with clean error should fail' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex 4287ed3fbb3..ba4c0442b85 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\ndiff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh\nindex bac90465406..760cf69087f 100755\n--- a/t/t0211-trace2-perf.sh\n+++ b/t/t0211-trace2-perf.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_PERF_BRIEF\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 4618ffc108e..5e0a1fa176d 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success 'basic: can write large commit message' '\n+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \tperl -e \"\ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex e2708e11d5b..fa1e2f9eef8 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success 'small block size fails with large reflog message' '\n+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 398865d6ebe..a574da3df53 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1270,7 +1270,7 @@ extract_batch_output () {\n     ' \"$@\"\n }\n \n-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '\n+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '\n \tgit cat-file --batch-all-objects --batch >actual.raw &&\n \textract_batch_output $orig <actual.raw >actual &&\n \t{\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex a0481139de5..b3cf53ff8c9 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '\n \tgrep \"too-short tree object\" err\n '\n \n-test_expect_success 'malformed mode in tree' '\n+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"9100644 \\0$bin_oid\" >tree-with-malformed-mode &&\n@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '\n \tgrep \"malformed mode in tree entry\" err\n '\n \n-test_expect_success 'empty filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"100644 \\0$bin_oid\" >tree-with-empty-filename &&\n@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '\n \tgrep \"empty filename in tree entry\" err\n '\n \n-test_expect_success 'duplicate filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \t{\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex c291a2b33d7..4977998e205 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n \tperl -e \"print reverse <>\" <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n \tperl -e \"print reverse <>\" <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\ndiff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh\nindex 8a456b1142d..01050453762 100755\n--- a/t/t1450-fsck.sh\n+++ b/t/t1450-fsck.sh\n@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '\n \ttest_grep ! \"fatal: empty filename in tree entry\" out\n '\n \n-test_expect_success 'tree entry with type mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \ttest_when_finished \"remove_object \\$commit\" &&\n@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '\n \ttest_grep ! \"dangling blob\" out\n '\n \n-test_expect_success 'tree entry with bogus mode' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \tblob=$(echo blob | git hash-object -w --stdin) &&\n@@ -984,7 +984,7 @@ corrupt_index_checksum () {\n \n # Corrupt the checksum on the index and then\n # verify that only fsck notices.\n-test_expect_success 'detect corrupt index file in fsck' '\n+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '\n \tcp .git/index .git/index.backup &&\n \ttest_when_finished \"mv .git/index.backup .git/index\" &&\n \tcorrupt_index_checksum &&\ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex f5bf16abcd8..502b1572059 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'ls-files -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-index -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-tree -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 3855d68dbc0..782d97fb7df 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-diff.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff various tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \tGIT_AUTHOR_DATE=\"2006-06-26 00:00:00 +0000\" &&\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 884f83fb8a4..2782b1fc183 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF\n ---\n EOF\n \n-test_expect_success 'no threading' '\n+test_expect_success PERL_TEST_HELPERS 'no threading' '\n \tgit checkout side &&\n \tcheck_threading expect.no-threading main\n '\n@@ -466,11 +466,11 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread' '\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success '--thread overrides format.thread=deep' '\n+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n@@ -490,7 +490,7 @@ In-Reply-To: <1>\n References: <1>\n EOF\n \n-test_expect_success 'thread in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '\n \tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n \t\t--thread main\n '\n@@ -512,7 +512,7 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '\n \tcheck_threading expect.cover-letter --cover-letter --thread main\n '\n \n@@ -538,12 +538,12 @@ References: <1>\n \t<0>\n EOF\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread main\n '\n \n-test_expect_success 'thread explicit shallow' '\n+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=shallow main\n '\n@@ -562,7 +562,7 @@ References: <0>\n \t<1>\n EOF\n \n-test_expect_success 'thread deep' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep' '\n \tcheck_threading expect.deep --thread=deep main\n '\n \n@@ -584,7 +584,7 @@ References: <1>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '\n \tcheck_threading expect.deep-irt  --thread=deep \\\n \t\t--in-reply-to=\"<test.message>\" main\n '\n@@ -609,7 +609,7 @@ References: <0>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '\n \tcheck_threading expect.deep-cl --cover-letter --thread=deep main\n '\n \n@@ -638,27 +638,27 @@ References: <1>\n \t<3>\n EOF\n \n-test_expect_success 'thread deep cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '\n \tcheck_threading expect.deep-cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=deep main\n '\n \n-test_expect_success 'thread via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread via config' '\n \ttest_config format.thread true &&\n \tcheck_threading expect.thread main\n '\n \n-test_expect_success 'thread deep via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.deep main\n '\n \n-test_expect_success 'thread config + override' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + override' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success 'thread config + --no-thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.no-threading --no-thread main\n '\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex f1efe482a59..189294de7ef 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet\n \n echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n \n-test_expect_success 'force diff with \"diff\"' '\n+test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success 'diff --cached' '\n+test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex 32b6e9a4e76..a92a42990b1 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success \"$test_description\" '\n+test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex daebf9796f5..c7d8eb12453 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex c4394a27b56..cbe50b15772 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success 'rewrite diff respects textconv' '\n+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n \tgrep \"dissimilarity index\" diff &&\n \tgrep \"^-61\" diff &&\ndiff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh\nindex 2fce4a98977..16266dff2af 100755\n--- a/t/t4058-diff-duplicates.sh\n+++ b/t/t4058-diff-duplicates.sh\n@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff duplicates tests; Perl not available'\n+\ttest_done\n+fi\n+\n # make_tree_entry <mode> <mode> <sha1>\n #\n # We have to rely on perl here because not all printfs understand\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex d370ecfe0d9..59d38793ae6 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply-binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 0784ba033a4..6f414ad27f5 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,6 +10,12 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply reverse tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 5e2b6c80eae..4794510d70d 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success 'am works with multi-line in-body headers' '\n+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex b0a3e849841..50fe8b0fd05 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rerere tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex f81e42a84d5..8f2ba98963f 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only \"key: value\" trail\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:unfold) unfolds trailers' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '\n \tgit log --no-walk --pretty=\"%(trailers:unfold)\" >actual &&\n \t{\n \t\tunfold <trailers &&\n@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success ':only and :unfold work together' '\n+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '\n \tgit log --no-walk --pretty=\"%(trailers:only,unfold)\" >actual &&\n \tgit log --no-walk --pretty=\"%(trailers:unfold,only)\" >reverse &&\n \ttest_cmp actual reverse &&\n@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '\n \tgit log --no-walk --pretty=\"format:%(trailers:key=Signed-Off-by,unfold)\" >actual &&\n \tunfold <trailers | grep Signed-off-by >expect &&\n \ttest_cmp expect actual\ndiff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh\nindex 3f163dc3969..8910d53cac1 100755\n--- a/t/t4216-log-bloom.sh\n+++ b/t/t4216-log-bloom.sh\n@@ -738,20 +738,20 @@ check_corrupt_graph () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'Bloom reader notices too-small data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '\n \tcheck_corrupt_graph BDAT clear 00000000 &&\n \techo \"warning: ignoring too-small changed-path chunk\" \\\n \t\t\"(4 < 12) in commit-graph file\" >expect.err &&\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '\n \tcheck_corrupt_graph BIDX 12 FFFFFFFF &&\n \t# use grep to avoid depending on exact chunk size\n \tgrep \"warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph\" err\n '\n \n-test_expect_success 'Bloom reader notices too-small index chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '\n \t# replace the index with a single entry, making most\n \t# lookups out-of-bounds\n \tcheck_corrupt_graph BIDX clear 00000000 &&\n@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-order index offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '\n \t# we do not know any real offsets, but we can pick\n \t# something plausible; we should not get to the point of\n \t# actually reading from the bogus offsets anyway.\ndiff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh\nindex 50344e17ca1..51749951916 100755\n--- a/t/t5004-archive-corner-cases.sh\n+++ b/t/t5004-archive-corner-cases.sh\n@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping archive corner cases tests; Perl not available'\n+\ttest_done\n+fi\n+\n # the 10knuls.tar file is used to test for an empty git generated tar\n # without having to invoke tar because an otherwise valid empty GNU tar\n # will be considered broken by {Open,Net}BSD tar\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 5ac8d39094b..143856c29f1 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,6 +7,12 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pack-object tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n \tperl -e \"print \\\"a\\\" x 4096;\" >a &&\ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex de58ca654a1..ac5e370e1e4 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first object' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n@@ -156,7 +156,7 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first delta' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 621bbbdd26e..81987296235 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex 32cf4227451..cd947b5a5ef 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -87,7 +87,7 @@ max_chain() {\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success 'packing produces a long delta' '\n+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth limits depth' '\n+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth=0 disables deltas' '\n+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'negative depth disables deltas' '\n+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\ndiff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh\nindex f68f64cd85e..0b3404f58fe 100755\n--- a/t/t5318-commit-graph.sh\n+++ b/t/t5318-commit-graph.sh\n@@ -837,7 +837,7 @@ check_corrupt_chunk () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \t# make it big enough that the graph file is plausible,\n \t# otherwise we hit an earlier check\n \tcheck_corrupt_chunk OIDF clear $(printf \"000000%02x\" $(test_seq 250)) &&\n@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices fanout/lookup table mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '\n \tcheck_corrupt_chunk OIDF 1020 \"FFFFFFFF\" &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph OID lookup chunk is the wrong size\n@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# Rather than try to corrupt a specific hash, we will just\n \t# wreck them all. But we cannot just set them all to 0xFFFFFFFF or\n \t# similar, as they are used for hi/lo starts in a binary search (so if\n@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small commit data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '\n \tcheck_corrupt_chunk CDAT clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph commit data chunk is wrong size\n@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds extra edge' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '\n \tcheck_corrupt_chunk EDGE clear &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph extra-edges pointer out of bounds\n@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small generations chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '\n \tcheck_corrupt_chunk GDA2 clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph generations chunk is wrong size\ndiff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh\nindex 0f215ad2e88..bd75dea9501 100755\n--- a/t/t5319-multi-pack-index.sh\n+++ b/t/t5319-multi-pack-index.sh\n@@ -1120,7 +1120,7 @@ corrupt_chunk () {\n \tcorrupt_chunk_file $midx \"$@\"\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \tcorrupt_chunk OIDF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small oid lookup chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '\n \tcorrupt_chunk OIDL clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small pack names chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '\n \t# There is no NUL to terminate the name here, so the\n \t# chunk is too short.\n \tcorrupt_chunk PNAM clear 70656666 &&\n@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader handles unaligned chunks' '\n+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '\n \t# A 9-byte PNAM means all of the subsequent chunks\n \t# will no longer be 4-byte aligned, but it is still\n \t# a valid one-pack chunk on its own (it is \"foo.pack\\0\").\n@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small object offset chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '\n \tcorrupt_chunk OOFF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader bounds-checks large offset table' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '\n \t# re-use the objects64 dir here to cheaply get access to a midx\n \t# with large offsets.\n \tgit init repo &&\n@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '\n \t)\n '\n \n-test_expect_success 'reader notices too-small revindex chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '\n \t# We only get a revindex with bitmaps (and likewise only\n \t# load it when they are asked for).\n \ttest_config repack.writeBitmaps true &&\n@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# This is similar to the out-of-bounds fanout test in t5318. The values\n \t# in adjacent entries should be large but not identical (they\n \t# are used as hi/lo starts for a binary search, which would then abort\ndiff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh\nindex a32be3867df..49a057cc2eb 100755\n--- a/t/t5324-split-commit-graph.sh\n+++ b/t/t5324-split-commit-graph.sh\n@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '\n \t)\n '\n \n-test_expect_success 'reader bounds-checks base-graph chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '\n \tgit clone --no-hardlinks . corrupt-base-chunk &&\n \t(\n \t\tcd corrupt-base-chunk &&\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex d27557b9b04..627f8b4efdc 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh\nindex a766a3e3f84..d8891e6a922 100755\n--- a/t/t5328-commit-graph-64bit-time.sh\n+++ b/t/t5328-commit-graph-64bit-time.sh\n@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '\n \tgit -C repo-uint32-max commit-graph verify\n '\n \n-test_expect_success 'reader notices out-of-bounds generation overflow' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '\n \tgraph=.git/objects/info/commit-graph &&\n \ttest_when_finished \"rm -rf $graph\" &&\n \tgit commit-graph write --reachable &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 3905cb6e4f1..1059ff45fe4 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\ndiff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh\nindex 3f81f16e133..571e8f1bc59 100755\n--- a/t/t5400-send-pack.sh\n+++ b/t/t5400-send-pack.sh\n@@ -268,7 +268,7 @@ extract_ref_advertisement () {\n \t'\n }\n \n-test_expect_success 'receive-pack de-dupes .have lines' '\n+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '\n \tgit init shared &&\n \tgit -C shared commit --allow-empty -m both &&\n \tgit clone -s shared fork &&\ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 0b28e4e452f..6a009fdcd71 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -20,7 +20,7 @@ extract_haves () {\n \tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n }\n \n-test_expect_success 'with core.alternateRefsCommand' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success 'with core.alternateRefsPrefixes' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nindex 845ca43ea0a..febe4410417 100755\n--- a/t/t5503-tagfollow.sh\n+++ b/t/t5503-tagfollow.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping tagfollow tests; Perl not available'\n+\ttest_done\n+fi\n+\n # End state of the repository:\n #\n #         T - tag1          S - tag2\ndiff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh\nindex 58074506c59..438250c75ed 100755\n--- a/t/t5504-fetch-receive-strict.sh\n+++ b/t/t5504-fetch-receive-strict.sh\n@@ -359,7 +359,7 @@ test_expect_success \\\n \tgrep \"Cannot demote unterminatedheader\" act\n '\n \n-test_expect_success 'badFilemode is not a strict error' '\n+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '\n \tgit init --bare badmode.git &&\n \ttree=$(\n \t\tcd badmode.git &&\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 5f350facf5e..432a2264e6f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -8,6 +8,12 @@ test_description='Per branch config variables affects \"git fetch\".\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-bundle.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch tests; Perl not available'\n+\ttest_done\n+fi\n+\n D=$(pwd)\n \n test_expect_success setup '\ndiff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh\nindex 37558226290..95d0f33b295 100755\n--- a/t/t5532-fetch-proxy.sh\n+++ b/t/t5532-fetch-proxy.sh\n@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch proxy tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup remote repo' '\n \tgit init remote &&\n \t(cd remote &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex c91a62b77af..342d0423c92 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 37f7547a4ca..77d20d19110 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\ndiff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh\nindex 761fdfcfe6c..b0d4ea78015 100755\n--- a/t/t5551-http-fetch-smart.sh\n+++ b/t/t5551-http-fetch-smart.sh\n@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n+\n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http fetch smart tests; Perl not available'\n+\ttest_done\n+fi\n+\n test \"$HTTP_PROTO\" = \"HTTP/2\" && enable_http2\n start_httpd\n \ndiff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh\nindex f3b158274c4..b6ee06f5c8f 100755\n--- a/t/t5562-http-backend-content-length.sh\n+++ b/t/t5562-http-backend-content-length.sh\n@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http backend content tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_lazy_prereq GZIP 'gzip --version'\n \n verify_http_result() {\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d0c18660e33..d743d986c40 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '\n \tgit -C replay.git index-pack -v --stdin <tmp.pack\n '\n \n-test_expect_success 'clone on case-insensitive fs' '\n+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '\n \tgit init icasefs &&\n \t(\n \t\tcd icasefs &&\n@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '\n \t)\n '\n \n-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '\n+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '\n \tgrep X icasefs/warning &&\n \tgrep x icasefs/warning &&\n \ttest_grep \"the following paths have collided\" icasefs/warning\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 46504519643..bc7e0fec8dc 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -751,7 +751,7 @@ replace_packfile () {\n \t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n }\n \n-test_expect_success 'upon cloning, check that all refs point to objects' '\n+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '\n+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 678a346ed06..200bf06ecb3 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'ignore very large set of prefixes' '\n+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex d3df81e7852..ad5e772cd72 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success 'when server sends \"ready\", expect DELIM' '\n+test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends \"ready\", expect DELIM' '\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n \tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n \ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex 191097171bc..f59d47aa6c6 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n+\ttest_done\n+fi\n+\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\ndiff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh\nindex d2cc69a17e4..9a420cf5605 100755\n--- a/t/t5710-promisor-remote-capability.sh\n+++ b/t/t5710-promisor-remote-capability.sh\n@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping promisor remote capabilities tests; Perl not available'\n+\ttest_done\n+fi\n+\n GIT_TEST_MULTI_PACK_INDEX=0\n GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0\n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex daa009c9a1b..5e1482aff78 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list bisect tests; Perl not available'\n+\ttest_done\n+fi\n+\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 0d7055d46d4..02dd4127aff 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list topo-order tests; Perl not available'\n+\ttest_done\n+fi\n+\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex bad02cf5b83..6131c361094 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 39793cbbd66..8074185742c 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success '--reverse --parents --full-history combines correctly' '\n+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n \tgit rev-list --parents --full-history main -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success '--boundary does too' '\n+test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n \tgit rev-list --boundary --parents --full-history main ^root -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 22dfd6d978e..eb98b3919c8 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list unexpected objects tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup well-formed objects' '\n \tblob=\"$(printf \"foo\" | git hash-object -w --stdin)\" &&\n \ttree=\"$(printf \"100644 blob $blob\\tfoo\" | git mktree)\" &&\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 3385fe9f130..6a74be576a2 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list disk usage tests; Perl not available'\n+\ttest_done\n+fi\n+\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex a5c77943854..732a4d3171e 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping for-each-ref tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 932c26cb45b..49aae183829 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success 'setup large log output' '\n+test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n \tperl -e \"\n \t\tprint \\\"this is a long commit message\\\" x 50000\n \t\" >commit-msg &&\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 0c605fd271a..14069600a2f 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping submodule dash URL tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex b2070d4e39f..14c41b2cb7c 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success 'status -z implies porcelain' '\n+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n \tgit status --porcelain |\n \tperl -pe \"s/\\012/\\000/g\" >expect &&\n \tgit status -z >output &&\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex 90ebb64f46e..b2730d200c8 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,6 +4,12 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping grep binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\ndiff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh\nindex d7167f55397..609845aeb1e 100755\n--- a/t/t8001-annotate.sh\n+++ b/t/t8001-annotate.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping annotate tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git annotate'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex e98993276a6..b40199df231 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 07a287ffd3e..5cb16872081 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,6 +4,12 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\ndiff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh\nindex c66494f5ba7..388057245c8 100755\n--- a/t/t8011-blame-split-file.sh\n+++ b/t/t8011-blame-split-file.sh\n@@ -81,7 +81,7 @@ do\n \t\tgit blame --root -C --$output combined >output\n \t'\n \n-\ttest_expect_success \"$output output finds correct commits\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output finds correct commits\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t5 base\n \t\t1 modified\n@@ -93,7 +93,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct filenames\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct filenames\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t11 one\n \t\t11 two\n@@ -102,7 +102,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct previous pointer\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct previous pointer\" '\n \t\tgenerate_expect >expect <<-EOF &&\n \t\t5 NONE\n \t\t1 $(git rev-parse modified^) one\ndiff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh\nindex c3a5f6d01ff..3d77352650f 100755\n--- a/t/t8012-blame-colors.sh\n+++ b/t/t8012-blame-colors.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex 067b15bad25..a9d38be997c 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success '(supposedly) non-conflicting change from SVN' '\n+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success 'change file but in unrelated area' \"\n+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n \tperl -i.bak -p -e 's/^4\\$/4444/' file &&\ndiff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh\nindex 40427883ec6..0781a8d6ace 100755\n--- a/t/t9350-fast-export.sh\n+++ b/t/t9350-fast-export.sh\n@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '\n \t(cd result && git show main:foo)\n '\n \n-test_expect_success 'fast-export quotes pathnames' '\n+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '\n \tgit init crazy-paths &&\n \ttest_config -C crazy-paths core.protectNTFS false &&\n \t(cd crazy-paths &&\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex 36566ace21b..f619b60f226 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'shell complains of overlong commands' '\n+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n \tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex a62699d6c79..59162a3c834 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1706,6 +1706,7 @@ test -n \"$USE_LIBPCRE2\" && test_set_prereq LIBPCRE2\n test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n test -n \"$SANITIZE_LEAK\" && test_set_prereq SANITIZE_LEAK\n test -n \"$GIT_VALGRIND_ENABLED\" && test_set_prereq VALGRIND\n+test -n \"$PERL_PATH\" && test_set_prereq PERL_TEST_HELPERS\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515005","messageId":"20250325-b4-pks-t-perlless-v2-8-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 08/20] meson: stop requiring Perl when tests are enabled","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:26Z","receivedAt":"2025-03-25T13:14:32Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Perl interpreter used to be a strict dependency for running our test\nsuite. This requirement is explicit in the Meson build system, where we\nrequire Perl to be present unless tests have been disabled.\n\nWith the preceding commits we have loosened this restriction so that it\nis now possible to run tests when Perl is unavailable. Loosen the above\nrequirement accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/meson.build b/meson.build\nindex efe2871c9db..d6e27b236fa 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -772,7 +772,7 @@ endif\n # features. It is optional if you want to neither execute tests nor use any of\n # these optional features.\n perl_required = get_option('perl')\n-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n   perl_required = true\n endif\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515006","messageId":"20250325-b4-pks-t-perlless-v2-7-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 07/20] t: adapt existing PERL prerequisites","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:25Z","receivedAt":"2025-03-25T13:14:32Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A couple of our tests depend on the PERL prerequisite even though it\nisn't needed. These tests fall into one of the following classes:\n\n  - The underlying logic used to be implemented in Perl but isn't\n    anymore. Here we can simply drop the dependency altogether.\n\n  - The test logic used to depend on Perl but doesn't anymore. Again, we\n    can simply drop the dependency.\n\n  - The test logic still relies on a Perl interpreter. These tests\n    should use the newly introduced PERL_TEST_HELPERS prerequisite.\n\nAdapt test cases accordingly.\n\nNote that in t1006 we have to introduce another new prerequisite\ndepending on whether or not the IPC::Open2 module is available. Funny\nenough, when starting to use `test_lazy_prereq` to do so we also get a\nconflict of variables with the \"script\" variable that contains the Perl\nlogic because `test_run_lazy_prereq_` also sets that variable. We thus\nrename the variable in t1006 to \"perl_script\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh                 | 10 +++++-----\n t/t0090-cache-tree.sh                 |  4 ++--\n t/t1006-cat-file.sh                   | 14 +++++++++-----\n t/t7501-commit-basic-functionality.sh |  6 +++---\n 4 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 9c3738ebb3f..4a892a91780 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'\n \t)\n '\n \n-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n+test_expect_success 'invalid process filter must fail (and not hang!)' '\n \ttest_config_global filter.protocol.process cat &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n@@ -1111,19 +1111,19 @@ do\n \tbranch) opt='-f HEAD' ;;\n \tesac\n \n-\ttest_expect_success PERL,TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress test_terminal git checkout $opt\n \t'\n \n-\ttest_expect_success PERL \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n+\ttest_expect_success \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! git checkout $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --quiet $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&\n \t\ttest_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt\n \t'\ndiff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh\nindex ab80c9ef135..d9015882946 100755\n--- a/t/t0090-cache-tree.sh\n+++ b/t/t0090-cache-tree.sh\n@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '\n \ttest_cache_tree\n '\n \n-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '\n+test_expect_success 'commit --interactive gives cache-tree on partial commit' '\n \ttest_when_finished \"git reset --hard\" &&\n \tcat <<-\\EOT >foo.c &&\n \tint foo()\n@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi\n \ttest_cache_tree expected.status\n '\n \n-test_expect_success PERL 'commit -p with shrinking cache-tree' '\n+test_expect_success 'commit -p with shrinking cache-tree' '\n \tmkdir -p deep/very-long-subdir &&\n \techo content >deep/very-long-subdir/file &&\n \tgit add deep &&\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex a574da3df53..0a22b0a7b8e 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '\n \tgrep \"^fatal:.*flush is only for --buffer mode.*\" err\n '\n \n-script='\n+perl_script='\n use warnings;\n use strict;\n use IPC::Open2;\n@@ -1345,12 +1345,16 @@ $? == 0 or die \"\\$?=$?\";\n \n expect=\"$hello_oid blob $hello_size\"\n \n-test_expect_success PERL '--batch-check is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-check $hello_oid \"$expect\"\n+test_lazy_prereq PERL_IPC_OPEN2 '\n+\tperl -MIPC::Open2 -e \"exit 0\"\n '\n \n-test_expect_success PERL '--batch-command info is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-check $hello_oid \"$expect\"\n+'\n+\n+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n '\n \n test_done\ndiff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh\nindex cc12f99f115..a37509f0043 100755\n--- a/t/t7501-commit-basic-functionality.sh\n+++ b/t/t7501-commit-basic-functionality.sh\n@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '\n \ttest_must_fail git commit -m foo -a file\n '\n \n-test_expect_success PERL 'can use paths with --interactive' '\n+test_expect_success 'can use paths with --interactive' '\n \techo bong-o-bong >file &&\n \t# 2: update, 1:st path, that is all, 7: quit\n \ttest_write_lines 2 1 \"\" 7 |\n@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '\n \tgrep Rubber.Duck output\n '\n \n-test_expect_success PERL 'interactive add' '\n+test_expect_success 'interactive add' '\n \techo 7 | test_must_fail git commit --interactive >out &&\n \tgrep \"What now\" out\n '\n \n-test_expect_success PERL \"commit --interactive doesn't change index if editor aborts\" '\n+test_expect_success \"commit --interactive doesn't change index if editor aborts\" '\n \techo zoo >file &&\n \ttest_must_fail git diff --exit-code >diff1 &&\n \ttest_write_lines u \"*\" q |\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515008","messageId":"20250325-b4-pks-t-perlless-v2-9-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 09/20] Makefile: stop requiring Perl when running tests","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:27Z","receivedAt":"2025-03-25T13:14:34Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Makefile for our tests has a couple of targets that depend on Perl.\nAdapt those targets to only run conditionally in case Perl is available\non the system so that it becomes possible to run the test suite without\nPerl.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/Makefile | 16 +++++++++++++---\n 1 file changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/t/Makefile b/t/Makefile\nindex 2994eb5fa9a..791e0a09789 100644\n--- a/t/Makefile\n+++ b/t/Makefile\n@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT\n \n all:: $(DEFAULT_TEST_TARGET)\n \n-test: pre-clean check-chainlint check-meson $(TEST_LINT)\n+test: pre-clean check-meson $(TEST_LINT)\n \t$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup\n \n+ifneq ($(PERL_PATH),)\n+test: check-chainlint\n+prove: check-chainlint\n+endif\n+\n failed:\n \t@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \\\n \t\tgrep -l '^failed [1-9]' *.counts | \\\n \t\tsed -n 's/\\.counts$$/.sh/p') && \\\n \ttest -z \"$$failed\" || $(MAKE) $$failed\n \n-prove: pre-clean check-chainlint $(TEST_LINT)\n+prove: pre-clean $(TEST_LINT)\n \t@echo \"*** prove (shell & unit tests) ***\"\n \t@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)\n \t$(MAKE) clean-except-prove-cache\n@@ -132,8 +137,13 @@ check-meson:\n \t\tfi; \\\n \tdone\n \n-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \\\n+test-lint: test-lint-duplicates test-lint-executable \\\n \ttest-lint-filenames\n+ifneq ($(PERL_PATH),)\n+test-lint: test-lint-shell-syntax\n+else\n+GIT_TEST_CHAIN_LINT = 0\n+endif\n ifneq ($(GIT_TEST_CHAIN_LINT),0)\n test-lint: test-chainlint\n endif\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515009","messageId":"20250325-b4-pks-t-perlless-v2-10-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 10/20] t: refactor tests depending on Perl transliteration operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:28Z","receivedAt":"2025-03-25T13:14:35Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform character\ntransliteration via the \"y/\" or \"tr/\" operator. These usecases can be\ntrivially replaced with tr(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-sha1.sh    |  4 ++--\n t/lib-diff.sh            |  4 ++--\n t/t3300-funny-names.sh   | 12 ++++++------\n t/t4020-diff-external.sh |  6 +++---\n t/t4103-apply-binary.sh  | 12 +++---------\n t/t4116-apply-reverse.sh | 10 ++--------\n t/t4200-rerere.sh        |  2 +-\n 7 files changed, 19 insertions(+), 31 deletions(-)\n\ndiff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh\nindex bf387d3db14..f03b784ddc2 100755\n--- a/t/helper/test-sha1.sh\n+++ b/t/helper/test-sha1.sh\n@@ -15,7 +15,7 @@ do\n \t\t\t{\n \t\t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\t\ttr \"\\000\" \"g\"\n \t\t\t} | ./t/helper/test-tool $sha1 $cnt\n \t\t)\n \t\tif test \"$expect\" = \"$actual\"\n@@ -61,7 +61,7 @@ do\n \t\t{\n \t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\ttr \"\\000\" \"g\"\n \t\t} | sha1sum |\n \t\tsed -e 's/ .*//'\n \t)\ndiff --git a/t/lib-diff.sh b/t/lib-diff.sh\nindex c4606bd4b7f..12b3c8fcc6a 100644\n--- a/t/lib-diff.sh\n+++ b/t/lib-diff.sh\n@@ -21,8 +21,8 @@ compare_diff_raw_z () {\n     # Also we do not check SHA1 hash generation in this test, which\n     # is a job for t0000-basic.sh\n \n-    perl -pe 'y/\\000/\\012/' <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n-    perl -pe 'y/\\000/\\012/' <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n+    tr \"\\000\" \"\\012\" <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n+    tr \"\\000\" \"\\012\" <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2\n }\n \ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex 502b1572059..dd0586b0073 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n+test_expect_success 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit ls-files -z >ls-files.z &&\n-\tperl -pe \"y/\\000/\\012/\" <ls-files.z >current &&\n+\ttr \"\\000\" \"\\012\" <ls-files.z >current &&\n \ttest_cmp expected current\n '\n \n@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n+test_expect_success 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-index -z --name-status $t0 >diff-index.z &&\n-\tperl -pe \"y/\\000/\\012/\" <diff-index.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-index.z >current &&\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n+test_expect_success 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-tree -z --name-status $t0 $t1 >diff-tree.z &&\n-\tperl -pe y/\\\\000/\\\\012/ <diff-tree.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-tree.z >current &&\n \ttest_cmp expected current\n '\n \ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex 189294de7ef..c8a23d51483 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet\n check_external_diff   1 empty  empty 1 on  --quiet\n check_external_diff 128 empty  error 2 on  --quiet\n \n-echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n+echo NULZbetweenZwords | tr \"Z\" \"\\000\" > file\n \n-test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n+test_expect_success 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n+test_expect_success 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex 59d38793ae6..8e302a5a57e 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply-binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\n@@ -32,10 +26,10 @@ test_expect_success 'setup' '\n \tgit commit -m \"Initial Version\" 2>/dev/null &&\n \n \tgit checkout -b binary &&\n-\tperl -pe \"y/x/\\000/\" <file1 >file3 &&\n+\ttr \"x\" \"\\000\" <file1 >file3 &&\n \tcat file3 >file4 &&\n \tgit add file2 &&\n-\tperl -pe \"y/\\000/v/\" <file3 >file1 &&\n+\ttr \"y\" \"\\000\" <file3 >file1 &&\n \trm -f file2 &&\n \tgit update-index --add --remove file1 file2 file3 file4 &&\n \tgit commit -m \"Second Version\" &&\n@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '\n \ttest -z \"$(git diff --name-status binary -- file3)\"\n '\n \n-test_expect_success 'reject truncated binary diff' '\n+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '\n \tdo_reset &&\n \n \t# this length is calculated to get us very close to\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 6f414ad27f5..1e7beab0016 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,23 +10,17 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply reverse tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\n-\tperl -pe \"y/ijk/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"ijk\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit add file1 file2 &&\n \tgit commit -m initial &&\n \tgit tag initial &&\n \n \ttest_write_lines a b c g h i J K L m o n p q >file1 &&\n-\tperl -pe \"y/mon/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"mon\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit commit -a -m second &&\n \tgit tag second &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 50fe8b0fd05..7fcca9ddad5 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '\n \n test_expect_success 'rerere clear' '\n \tmv $rr/postimage .git/post-saved &&\n-\techo \"$sha1\ta1\" | perl -pe \"y/\\012/\\000/\" >.git/MERGE_RR &&\n+\techo \"$sha1\ta1\" | tr \"\\012\" \"\\000\" >.git/MERGE_RR &&\n \tgit rerere clear &&\n \t! test -d $rr\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515010","messageId":"20250325-b4-pks-t-perlless-v2-11-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:29Z","receivedAt":"2025-03-25T13:14:35Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform substitution via the\n\"s/\" operator. These usecases can be trivially replaced with sed(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        | 10 ++--------\n t/t4029-diff-trailing-space.sh            |  5 +++--\n t/t4200-rerere.sh                         | 12 +++---------\n t/t5303-pack-corruption-resilience.sh     | 10 ++++++----\n t/t5310-pack-bitmaps.sh                   |  4 ++--\n t/t5534-push-signed.sh                    |  4 ++--\n t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------\n t/t7416-submodule-dash-url.sh             |  9 ++-------\n t/t7508-status.sh                         |  4 ++--\n t/t8006-blame-textconv.sh                 |  8 +-------\n t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------\n 11 files changed, 40 insertions(+), 60 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex 1aaa6bf5ae8..273d71411fe 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,12 +5,6 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping ignores tests; Perl not available'\n-\ttest_done\n-fi\n-\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\n@@ -45,11 +39,11 @@ test_stderr () {\n }\n \n broken_c_unquote () {\n-\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n+\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n }\n \n broken_c_unquote_verbose () {\n-\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n+\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n }\n \n stderr_contains () {\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex a92a42990b1..db75998e35f 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n+test_expect_success \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\n@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tgit config --bool diff.suppressBlankEmpty true &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\n-\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n+\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n+\tmv exp.munged exp &&\n \tgit config --bool diff.suppressBlankEmpty false &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 7fcca9ddad5..bacb93d014f 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rerere tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\n@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n \ttest_might_fail git config --unset rerere.enabled &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep \"^=======\\$\" $rr/preimage &&\n \t! test -f $rr/postimage &&\n@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep ^=======$ $rr/preimage\n '\n@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n \tgit config rerere.enabled true &&\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1\n '\n \ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex ac5e370e1e4..07382797bbb 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n+test_expect_success 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n+\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n@@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n+test_expect_success 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n+\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \tgit cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 81987296235..9033d72b8c7 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -421,7 +421,7 @@ test_bitmap_cases () {\n \n \t\t\t# mark the commits which did not receive bitmaps as preferred,\n \t\t\t# and generate the bitmap again\n-\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n \t\t\t\tgit update-ref --stdin &&\n \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n \ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 342d0423c92..d5c0d00114e 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n \t# Tweak the push output to make the push option outside the cert\n \t# different, then replay it on a fresh dst, checking that ff is not\n \t# deleted.\n-\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n \tgit -C dst config receive.advertisepushoptions 1 &&\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex 6131c361094..12329aab388 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\n@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n    first_commit=$(git rev-parse HEAD~3)\n    '\n \n-test_expect_success 'corrupt second commit object' \\\n-   '\n-   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n-   test_must_fail git fsck --full\n-   '\n+test_expect_success 'corrupt second commit object' '\n+\tfor p in .git/objects/pack/*.pack\n+\tdo\n+\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n+\t\tmv \"$p.munged\" \"$p\" ||\n+\t\treturn 1\n+\tdone &&\n+\ttest_must_fail git fsck --full\n+'\n \n test_expect_success 'rev-list should fail' '\n \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 14069600a2f..00b81d349b9 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping submodule dash URL tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\n@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n '\n \n test_expect_success 'remove ./ protection from .gitmodules url' '\n-\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n+\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n+\tmv .gitmodules.munged .gitmodules &&\n \tgit commit -am \"drop protection\"\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 14c41b2cb7c..cdc1d6fcc78 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n+test_expect_success 'status -z implies porcelain' '\n \tgit status --porcelain |\n-\tperl -pe \"s/\\012/\\000/g\" >expect &&\n+\ttr \"\\012\" \"\\000\" >expect &&\n \tgit status -z >output &&\n \ttest_cmp expect output\n '\ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 5cb16872081..810dac18f56 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,12 +4,6 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping blame textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\n@@ -17,7 +11,7 @@ find_blame() {\n cat >helper <<'EOF'\n #!/bin/sh\n grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n-\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n+sed 's/^bin: /converted: /' <\"$1\"\n EOF\n chmod +x helper\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex a9d38be997c..9afdb45b1cc 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n+test_expect_success '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n \t(cd tmp &&\n-\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n-\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n+\t\tmv file.munged file &&\n \t\tpoke file &&\n \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n+test_expect_success 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n-\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n-\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n+\tsed -e 's/^4\\$/4444/' \\\n+\t    -e 's/^7\\$/7777/' \\\n+\t\t<file >file.munged &&\n+\tmv file.munged file &&\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n \tgit commit -m '4 => 4444, 7 => 7777' file &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515011","messageId":"20250325-b4-pks-t-perlless-v2-13-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:31Z","receivedAt":"2025-03-25T13:14:36Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of tests that depend on Perl for textconv scripts.\nRefactor these tests to instead be implemented via shell utilities so\nthat we can drop a couple of PERL_TEST_HELPERS prerequisites.\n\nNote that not all of the conversions are a one-to-one equivalent to the\nprevious textconv scripts. But that's not really needed in the first\nplace: we only care that the textconv script does something, and that\ncan be verified trivially without having a full-blown invocation of\nhexdump. So at times, the implementation of the textconv scripts is\nreduced to their bare minimum and the expectations of those tests are\nadapted accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t4030-diff-textconv.sh       | 15 +++------------\n t/t4031-diff-rewrite-binary.sh | 19 +++++++------------\n t/t7815-grep-binary.sh         | 15 +++------------\n 3 files changed, 13 insertions(+), 36 deletions(-)\n\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex c7d8eb12453..f904fc19f69 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping diff textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\n@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n +1\n EOF\n \n-cat >hexdump <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-chmod +x hexdump\n-\n test_expect_success 'setup binary file with history' '\n+\twrite_script hexdump <<-\\EOF &&\n+\ttr \"\\000\\001\" \"01\" <\"$1\"\n+\tEOF\n \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n '\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex cbe50b15772..15e012ccc7c 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n \tgrep \" rewrite file\" diff\n '\n \n-{\n-\techo \"#!$SHELL_PATH\"\n-\tcat <<'EOF'\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-} >dump\n-chmod +x dump\n-\n test_expect_success 'setup textconv' '\n+\twrite_script dump <<-\\EOF &&\n+\ttest-tool hexdump <\"$1\"\n+\tEOF\n \techo file diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n+test_expect_success 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n-\tgrep \"dissimilarity index\" diff &&\n-\tgrep \"^-61\" diff &&\n-\tgrep \"^-0\" diff\n+\ttest_grep \"dissimilarity index\" diff &&\n+\ttest_grep \"^-3d 0a 00\" diff &&\n+\ttest_grep \"^+3d 0a 01\" diff\n '\n \n test_done\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex b2730d200c8..3bd91da9707 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,12 +4,6 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping grep binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\n@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n \ttest_cmp expect actual\n '\n \n-cat >nul_to_q_textconv <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n-EOF\n-chmod +x nul_to_q_textconv\n-\n test_expect_success 'setup textconv filters' '\n+\twrite_script nul_to_q_textconv <<-\\EOF &&\n+\ttr \"\\000\" \"Q\" <\"$1\"\n+\tEOF\n \techo a diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515012","messageId":"20250325-b4-pks-t-perlless-v2-12-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:30Z","receivedAt":"2025-03-25T13:14:36Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A bunch of tests rely on Perl to print data in various different ways.\nThese usages fall into the following categories:\n\n  - Print data conditionally by matching patterns. These usecases can be\n    converted to use awk(1) rather easily.\n\n  - Print data repeatedly. These usecases can typically be converted to\n    use a combination of `test-tool genzeros` and sed(1).\n\n  - Print data in reverse. These usecases can be converted to use\n    awk(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0610-reftable-basics.sh          |  7 +++----\n t/t0613-reftable-write-options.sh   |  4 ++--\n t/t1010-mktree.sh                   |  8 ++++----\n t/t4150-am.sh                       | 10 +++++-----\n t/t5300-pack-object.sh              | 16 +++++-----------\n t/t5326-multi-pack-bitmaps.sh       |  6 +++---\n t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------\n t/t5410-receive-pack-alternates.sh  |  6 +++---\n t/t5701-git-serve.sh                |  7 +++++--\n t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------\n t/t6115-rev-list-du.sh              |  8 +-------\n t/t7006-pager.sh                    |  8 ++++----\n t/t8002-blame.sh                    |  2 +-\n t/t9850-shell.sh                    |  4 ++--\n 14 files changed, 51 insertions(+), 67 deletions(-)\n\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 5e0a1fa176d..77ed11e7172 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n+test_expect_success 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+\n+\tawk \"BEGIN { for (i = 0; i < 50000; i++) printf \\\"%s\\\", \\\"this is a long commit message\\\" }\" >commit-msg &&\n \tgit -C repo commit --allow-empty --file=../commit-msg\n '\n \ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex fa1e2f9eef8..42aa1592f87 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n+test_expect_success 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\n \t\tcd repo &&\n \t\ttest_commit A &&\n-\t\tperl -e \"print \\\"a\\\" x 500\" >logmsg &&\n+\t\ttest-tool genzeros 500 | tr \"\\000\" \"a\" >logmsg &&\n \t\tcat >expect <<-EOF &&\n \t\tfatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large\n \t\tEOF\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex 4977998e205..e9973f74949 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n-\tperl -e \"print reverse <>\" <top |\n+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+\tsort -r <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n-\tperl -e \"print reverse <>\" <top.withsub |\n+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+\tsort -r <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\n '\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 4794510d70d..2ae93d3c967 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n+test_expect_success 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\n@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'\n     Body test\" --author=\"$LONG <long@example.com>\" &&\n \tgit format-patch --stdout -1 >patch &&\n \t# bump from, date, and subject down to in-body header\n-\tperl -lpe \"\n-\t\tif (/^From:/) {\n+\tawk \"\n+\t\t/^From:/{\n \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n \t\t\tprint \\\"Subject: x\\n\\\";\n-\t\t}\n-\t\" patch >msg &&\n+\t\t}; 1\n+\t\" <patch >msg &&\n \tgit checkout HEAD^ &&\n \tgit am msg &&\n \t# Ensure that the author and full message are present\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 143856c29f1..362b05441af 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,17 +7,11 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pack-object tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n-\tperl -e \"print \\\"a\\\" x 4096;\" >a &&\n-\tperl -e \"print \\\"b\\\" x 4096;\" >b &&\n-\tperl -e \"print \\\"c\\\" x 4096;\" >c &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"a\" >a &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"b\" >b &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"c\" >c &&\n \ttest-tool genrandom \"seed a\" 2097152 >a_big &&\n \ttest-tool genrandom \"seed b\" 2097152 >b_big &&\n \tgit update-index --add a a_big b b_big c &&\n@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'\n # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>\n # e.g.: check_deltas stderr -gt 0\n check_deltas() {\n-\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' <\"$1\") &&\n \tshift &&\n \tif ! test \"$deltas\" \"$@\"\n \tthen\n@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '\n \tcheck_unpack test-3-${packname_3} obj-list \"$BATCH_CONFIGURATION\"\n '\n \n-test_expect_success 'compare delta flavors' '\n+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '\n \tperl -e '\\''\n \t\tdefined($_ = -s $_) or die for @ARGV;\n \t\texit 1 if $ARGV[0] <= $ARGV[1];\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex 627f8b4efdc..e5d52de4bd3 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {\n \t\t\tcomm -13 bitmaps commits >before &&\n \t\t\ttest_line_count = 1 before &&\n \n-\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n-\t\t\t\t<before | git update-ref --stdin &&\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n+\t\t\tgit update-ref --stdin &&\n \n \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n \t\t\trm -fr $midx &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 1059ff45fe4..df13a18c5c7 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\n@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {\n \n tag_everything () {\n \tgit rev-list --all --no-object-names >in &&\n-\tperl -lne '\n-\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n-\t' <in | git update-ref --stdin\n+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' <in |\n+\tgit update-ref --stdin\n }\n \n test_expect_success 'setup' '\n@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n \ttest_config bitmapPseudoMerge.test.pattern \"refs/tags/\" &&\n \ttest_config bitmapPseudoMerge.test.maxMerges 1 &&\n \ttest_config bitmapPseudoMerge.test.stableThreshold never &&\n@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\t\ttest_commit_bulk 16 &&\n \n \t\t\tgit rev-list HEAD~16.. >in &&\n-\n-\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" <in |\n \t\t\tgit update-ref --stdin || return 1\n \t\tdone &&\n \n@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\tdo\n \t\t\ttest_pseudo_merge_commits $m >oids &&\n \t\t\tgrep -f oids refs |\n-\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n+\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n \t\t\tsort -u || return 1\n \t\tdone >remotes &&\n \ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 6a009fdcd71..4e82fd102e3 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -17,10 +17,10 @@ test_expect_success 'setup' '\n '\n \n extract_haves () {\n-\tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n+\tdepacketize | sed -n 's/^\\([^ ][^ ]*\\) \\.have/\\1/p'\n }\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n+test_expect_success 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n+test_expect_success 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 200bf06ecb3..d4c28bae39e 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n+test_expect_success 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\n@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t\techo command=ls-refs &&\n \t\techo object-format=$(test_oid algo) &&\n \t\techo 0001 &&\n-\t\tperl -le \"print \\\"ref-prefix refs/heads/\\$_\\\" for (1..65536)\" &&\n+\t\tawk \"{\n+\t\t\tfor (i = 1; i <= 65536; i++)\n+\t\t\t\tprint \\\"ref-prefix refs/heads/\\\", \\$i\n+\t\t}\" &&\n \t\techo 0000\n \t} |\n \ttest-tool pkt-line pack >in &&\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 8074185742c..273196f52b5 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n-\tgit rev-list --parents --full-history main -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+reverse () {\n+\tawk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'\n+}\n+\n+test_expect_success '--reverse --parents --full-history combines correctly' '\n+\tgit rev-list --parents --full-history main -- foo | reverse >expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n \t\t> actual &&\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n-\tgit rev-list --boundary --parents --full-history main ^root -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+test_expect_success '--boundary does too' '\n+\tgit rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\n \t\tmain ^root -- foo > actual &&\n \ttest_cmp expected actual\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 6a74be576a2..04c577dad69 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list disk usage tests; Perl not available'\n-\ttest_done\n-fi\n-\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\n@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '\n disk_usage_slow () {\n \tgit rev-list --no-object-names \"$@\" |\n \tgit cat-file --batch-check=\"%(objectsize:disk)\" |\n-\tperl -lne '$total += $_; END { print $total}'\n+\tawk '{ i += $1 } END { print i }'\n }\n \n # check behavior with given rev-list options; note that\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 49aae183829..9717e825f0d 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+test_expect_success 'setup large log output' '\n+\ttest-tool genzeros 50000 |\n+\ttr \"\\000\" \"a\" |\n+\tsed \"s/a/this is a long commit message/g\" >commit-msg &&\n \tgit commit --allow-empty -F commit-msg\n '\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex b40199df231..0b7548c8e75 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '\n \t\texpect=$1 && shift &&\n \t\techo $sha1 | cut -c 1-$expect >expect &&\n \t\tgit blame \"$@\" abbrev.t >actual &&\n-\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" <actual >actual.sha &&\n \t\ttest_cmp expect actual.sha\n \t}\n '\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex f619b60f226..21c3af48bd0 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n-\tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n+test_expect_success 'shell complains of overlong commands' '\n+\ttest-tool genzeros | tr \"\\000\" \"a\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515013","messageId":"20250325-b4-pks-t-perlless-v2-14-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:32Z","receivedAt":"2025-03-25T13:14:37Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\nstdin. Refactor it to instead use awk(1) so that we drop the\nPERL_TEST_HELPERS prerequisite in users of this library.\n\nNote that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\nnow that the test suite doesn't bail out early anymore in case the\nprerequisite isn't set.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-gpg.sh            |  6 +-----\n t/t6300-for-each-ref.sh | 21 ++++++++++-----------\n 2 files changed, 11 insertions(+), 16 deletions(-)\n\ndiff --git a/t/lib-gpg.sh b/t/lib-gpg.sh\nindex 3845b6ac449..937b876bd05 100644\n--- a/t/lib-gpg.sh\n+++ b/t/lib-gpg.sh\n@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '\n '\n \n sanitize_pgp() {\n-\tperl -ne '\n-\t\t/^-----END PGP/ and $in_pgp = 0;\n-\t\tprint unless $in_pgp;\n-\t\t/^-----BEGIN PGP/ and $in_pgp = 1;\n-\t'\n+\tsed \"/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}\"\n }\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 732a4d3171e..5db7038c417 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping for-each-ref tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\n@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '\n \ttest_must_fail git for-each-ref --format=\"%(raw)\" --tcl\n '\n \n-test_expect_success '%(raw) with --perl' '\n+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '\n \tgit for-each-ref --format=\"\\$name= %(raw);\n print \\\"\\$name\\\"\" refs/myblobs/blob1 --perl | perl >actual &&\n \tcmp blob1 actual &&\n@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '\n '\n \n test_trailer_option () {\n+\tif test \"$#\" -eq 3\n+\tthen\n+\t\tprereq=\"$1\"\n+\t\tshift\n+\tfi &&\n \ttitle=$1 option=$2\n \tcat >expect\n-\ttest_expect_success \"$title\" '\n+\ttest_expect_success $prereq \"$title\" '\n \t\tgit for-each-ref --format=\"%($option)\" refs/heads/main >actual &&\n \t\ttest_cmp expect actual &&\n \t\tgit for-each-ref --format=\"%(contents:$option)\" refs/heads/main >actual &&\n@@ -1452,7 +1451,7 @@ test_trailer_option () {\n \t'\n }\n \n-test_trailer_option '%(trailers:unfold) unfolds trailers' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \\\n \t'trailers:unfold' <<-EOF\n \t$(unfold <trailers)\n \n@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \\\n \n \tEOF\n \n-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \\\n \t'trailers:only,unfold' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n \tEOF\n \n-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \\\n \t'trailers:unfold,only' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515014","messageId":"20250325-b4-pks-t-perlless-v2-15-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:33Z","receivedAt":"2025-03-25T13:14:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `name_from_description()` test helper uses Perl to munge a given\ndescription and convert it into a name. Refactor it to instead use a\ncombination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\nprerequisites in users of this library.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-t6000.sh                 | 13 ++++++-------\n t/t6002-rev-list-bisect.sh     |  6 ------\n t/t6003-rev-list-topo-order.sh |  6 ------\n 3 files changed, 6 insertions(+), 19 deletions(-)\n\ndiff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\nindex fba6778ca35..35c54724650 100644\n--- a/t/lib-t6000.sh\n+++ b/t/lib-t6000.sh\n@@ -109,13 +109,12 @@ check_output () {\n # All alphanums translated into -'s which are then compressed and stripped\n # from front and back.\n name_from_description () {\n-\tperl -pe '\n-\t\ts/[^A-Za-z0-9.]/-/g;\n-\t\ts/-+/-/g;\n-\t\ts/-$//;\n-\t\ts/^-//;\n-\t\ty/A-Z/a-z/;\n-\t'\n+\tsed \\\n+\t\t-e 's/[^A-Za-z0-9.]/-/g' \\\n+\t\t-e 's/--*/-/g' \\\n+\t\t-e 's/-$//' \\\n+\t\t-e 's/^-//' \\\n+\t\t-e 'y/A-Z/a-z/'\n }\n \n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex 5e1482aff78..daa009c9a1b 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list bisect tests; Perl not available'\n-\ttest_done\n-fi\n-\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 02dd4127aff..0d7055d46d4 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list topo-order tests; Perl not available'\n-\ttest_done\n-fi\n-\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515015","messageId":"20250325-b4-pks-t-perlless-v2-16-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 16/20] t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:34Z","receivedAt":"2025-03-25T13:14:40Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our Apache HTTPD setup exposes an \"one_time_perl\" endpoint to access\nrepositories. If used, we execute the \"apply-one-time-perl.sh\" CGI\nscript that checks whether we have a \"one-time-perl\" script. If so, that\nscript gets executed so that it can munge what would be served. Once\ndone, the script gets removed so that it doesn't execute a second time.\n\nAs the name says, this functionality expects the user to pass a Perl\nscript. This isn't really necessary though: we can just as easily\nimplement the same thing with arbitrary scripts.\n\nRefactor the code so that we instead expect an arbitrary script to\nexist and rename the functionality to \"one-time-script\". Adapt callers\nto use shell utilities instead of Perl so that we can drop the\nPERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-httpd.sh                       |  2 +-\n t/lib-httpd/apache.conf              |  6 ++---\n t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------\n t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++\n t/t5537-fetch-shallow.sh             | 17 ++++++-------\n t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------\n t/t5702-protocol-v2.sh               | 27 +++++++++++---------\n t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---\n 8 files changed, 86 insertions(+), 77 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex d83bafeab32..5091db949b7 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -165,7 +165,7 @@ prepare_httpd() {\n \tinstall_script broken-smart-http.sh\n \tinstall_script error-smart-http.sh\n \tinstall_script error.sh\n-\tinstall_script apply-one-time-perl.sh\n+\tinstall_script apply-one-time-script.sh\n \tinstall_script nph-custom-auth.sh\n \n \tln -s \"$LIB_HTTPD_MODULE_PATH\" \"$HTTPD_ROOT_PATH/modules\"\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex 022276a6b9a..e631ab0eb5e 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n-<LocationMatch /one_time_perl/>\n+<LocationMatch /one_time_script/>\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n ScriptAlias /error_smart/ error-smart-http.sh/\n ScriptAlias /error/ error.sh/\n-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1\n+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1\n ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Directory ${GIT_EXEC_PATH}>\n \tOptions FollowSymlinks\n@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Files error.sh>\n   Options ExecCGI\n </Files>\n-<Files apply-one-time-perl.sh>\n+<Files apply-one-time-script.sh>\n \tOptions ExecCGI\n </Files>\n <Files ${GIT_EXEC_PATH}/git-http-backend>\ndiff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh\ndeleted file mode 100644\nindex d7f9fed6aee..00000000000\n--- a/t/lib-httpd/apply-one-time-perl.sh\n+++ /dev/null\n@@ -1,27 +0,0 @@\n-#!/bin/sh\n-\n-# If \"one-time-perl\" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,\n-# using the contents of \"one-time-perl\" as the perl command to be run. If the\n-# response was modified as a result, delete \"one-time-perl\" so that subsequent\n-# HTTP responses are no longer modified.\n-#\n-# This can be used to simulate the effects of the repository changing in\n-# between HTTP request-response pairs.\n-if test -f one-time-perl\n-then\n-\tLC_ALL=C\n-\texport LC_ALL\n-\n-\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n-\t\"$PERL_PATH\" -pe \"$(cat one-time-perl)\" out >out_modified\n-\n-\tif cmp -s out out_modified\n-\tthen\n-\t\tcat out\n-\telse\n-\t\tcat out_modified\n-\t\trm one-time-perl\n-\tfi\n-else\n-\t\"$GIT_EXEC_PATH/git-http-backend\"\n-fi\ndiff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh\nnew file mode 100644\nindex 00000000000..b1682944e28\n--- /dev/null\n+++ b/t/lib-httpd/apply-one-time-script.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+# If \"one-time-script\" exists in $HTTPD_ROOT_PATH, run the script on the HTTP\n+# response. If the response was modified as a result, delete \"one-time-script\"\n+# so that subsequent HTTP responses are no longer modified.\n+#\n+# This can be used to simulate the effects of the repository changing in\n+# between HTTP request-response pairs.\n+if test -f one-time-script\n+then\n+\tLC_ALL=C\n+\texport LC_ALL\n+\n+\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n+\t./one-time-script out >out_modified\n+\n+\tif cmp -s out out_modified\n+\tthen\n+\t\tcat out\n+\telse\n+\t\tcat out_modified\n+\t\trm one-time-script\n+\tfi\n+else\n+\t\"$GIT_EXEC_PATH/git-http-backend\"\n+fi\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 77d20d19110..9dfcfb46df0 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\n@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before\n \tgit -C \"$REPO\" config protocol.version 2 &&\n \tgit -C client config protocol.version 2 &&\n \n-\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_perl/repo\" main:a_branch &&\n+\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_script/repo\" main:a_branch &&\n \n \t# Craft a situation in which the server sends back an unshallow request\n \t# with an empty packfile. This is done by refetching with a shorter\n \t# depth (to ensure that the packfile is empty), and overwriting the\n \t# shallow line in the response with the unshallow line we want.\n-\tprintf \"$(test_oid perl)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n-\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" <\"\\$1\"\n+\tEOF\n \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n-\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n+\t\tfetch --depth=1 \"$HTTPD_URL/one_time_script/repo\" \\\n \t\tmain:a_branch &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\" &&\n \n \t# Ensure that the resulting repo is consistent, despite our failure to\n \t# fetch.\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex bc7e0fec8dc..f878592a377 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -737,21 +737,25 @@ intersperse () {\n \tsed 's/\\(..\\)/'$1'\\1/g'\n }\n \n-# Create a one-time-perl command to replace the existing packfile with $1.\n+# Create a one-time-script command to replace the existing packfile with $1.\n replace_packfile () {\n-\t# The protocol requires that the packfile be sent in sideband 1, hence\n-\t# the extra \\x01 byte at the beginning.\n-\tcp $1 \"$HTTPD_ROOT_PATH/one-time-pack\" &&\n-\techo 'if (/packfile/) {\n-\t\tprint;\n-\t\tmy $length = -s \"one-time-pack\";\n-\t\tprintf \"%04x\\x01\", $length + 5;\n-\t\tprint `cat one-time-pack` . \"0000\";\n-\t\tlast\n-\t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\tcp \"$1\" one-time-pack &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tif grep packfile \"\\$1\" >/dev/null\n+\tthen\n+\t\tsed '/packfile/q' <\"\\$1\" &&\n+\t\t# The protocol requires that the packfile be sent in sideband\n+\t\t# 1, hence the extra \\001 byte at the beginning.\n+\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n+\t\tcat \"$PWD/one-time-pack\" &&\n+\t\tprintf \"0000\"\n+\telse\n+\t\tcat \"\\$1\"\n+\tfi\n+\tEOF\n }\n \n-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n+test_expect_success 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t\n \t# section header.\n \ttest_config -C \"$SERVER\" protocol.version 2 &&\n \ttest_must_fail git -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&\n \n \ttest_grep \"did not send all necessary objects\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not\n \n \t# Exercise to make sure it works.\n \tgit -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&\n \t! grep \"missing object referenced by\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \n \t# Clone. The client has deltabase_have but not deltabase_missing.\n \tgit -c protocol.version=2 clone --no-checkout \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo &&\n \tgit -C repo hash-object -w -- \"$SERVER/have.txt\" &&\n \n \t# Sanity check to ensure that the client does not have\n@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \tgrep \"want $(cat deltabase_missing)\" trace &&\n \t! grep \"want $(cat deltabase_have)\" trace &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n # DO NOT add non-httpd-specific tests here, because the last part of this\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex ad5e772cd72..27434b1f07a 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n+test_expect_success 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM'\n \n \t# After \"ready\" in the acknowledgments section, pretend that a FLUSH\n \t# (0000) was sent instead of a DELIM (0001).\n-\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/ready/{n;s/0001/0000/;}\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail git -C http_child -c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect\n \n \t# After the acknowledgments section, pretend that a DELIM\n \t# (0001) was sent instead of a FLUSH (0000).\n-\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n \t\t-c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \tgrep \"fetch< .*acknowledgments\" log &&\n \t! grep \"fetch< .*ready\" log &&\n \ttest_grep \"expected no other sections to be sent after no .ready.\" err\n@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n-\tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n+\tURI=\"$HTTPD_URL/one_time_script/server\" &&\n \n \tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n \n-\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" <\"$1\"\n+\tEOF\n \n \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n \t\t--no-tags \\\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex f59d47aa6c6..ac7266126a0 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '\n \t\ttest_commit m3 &&\n \t\tgit tag -d m2 m3\n \t) &&\n-\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo\" &&\n+\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo\" &&\n \tgit -C \"$LOCAL_PRISTINE\" config protocol.version 2\n '\n \n@@ -481,7 +481,9 @@ inconsistency () {\n \t# RPCs during a single negotiation.\n \toid1=$(git -C \"$REPO\" rev-parse $1) &&\n \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n-\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tsed \"s/$oid1/$oid2/\" <\"\\$1\"\n+\tEOF\n }\n \n test_expect_success 'server is initially ahead - no ref in want' '\n@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n-\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/main/rain/\" <\"$1\"\n+\tEOF\n \ttest_must_fail git -C local fetch 2>err &&\n \n \ttest_grep \"fatal: remote error: unknown ref refs/heads/rain\" err\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515017","messageId":"20250325-b4-pks-t-perlless-v2-17-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:35Z","receivedAt":"2025-03-25T13:14:41Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `generate_random_characters()` helper function generates N\nrandom characters in the range 'a-z' and writes them into a file. The\nlogic currently uses Perl, but it can be adapted rather easily by:\n\n  - Making `test-tool genrandom` generate an infinite stream.\n\n  - Using `tr -dc` to strip all characters which aren't in the range of\n    'a-z'.\n\n  - Using `test_copy_bytes()` to copy the first N bytes.\n\nThis allows us to drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 4a892a91780..bf10d253ec4 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -20,8 +20,7 @@ EOF\n generate_random_characters () {\n \tLEN=$1\n \tNAME=$2\n-\ttest-tool genrandom some-seed $LEN |\n-\t\tperl -pe \"s/./chr((ord($&) % 26) + ord('a'))/sge\" >\"$TEST_ROOT/$NAME\"\n+\ttest-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes \"$LEN\" >\"$TEST_ROOT/$NAME\"\n }\n \n filter_git () {\n@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n+test_expect_success 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n+test_expect_success 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515016","messageId":"20250325-b4-pks-t-perlless-v2-18-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 18/20] t0210: refactor trace2 scrubbing to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:36Z","receivedAt":"2025-03-25T13:14:42Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The output generated by our trace2 mechanism contains several fields\nthat are dependent on the environment they're being run in, which makes\nit somewhat harder to test it. As a countermeasure we scrub the output\nand strip out any fields that contain such information.\n\nThe logic to do so is implemented in Perl, but it can be trivially\nported to instead use sed(1). Refactor the code accordingly so that we\ncan drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------\n t/t0210/scrub_normal.perl | 54 -----------------------------------------\n 2 files changed, 43 insertions(+), 72 deletions(-)\n\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex ba4c0442b85..96c68f65df2 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping trace2 tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\n@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF\n #\n # Implicit return from cmd_<verb> function propagates <code>.\n \n+scrub_normal () {\n+\t# Scrub the variable fields from the normal trace2 output to make\n+\t# testing easier:\n+\t#\n+\t#   1. Various messages include an elapsed time in the middle of the\n+\t#      message. Replace the time with a placeholder to simplify our\n+\t#      HEREDOC in the test script.\n+\t#\n+\t#   2. We expect:\n+\t#\n+\t#        start <argv0> [<argv1> [<argv2> [...]]]\n+\t#\n+\t#      where argv0 might be a relative or absolute path, with or\n+\t#      without quotes, and platform dependent. Replace argv0 with a\n+\t#      token for HEREDOC matching in the test script.\n+\t#\n+\t#   3. Likewise, the 'cmd_path' message breaks out argv[0].\n+\t#\n+\t#      This line is only emitted when RUNTIME_PREFIX is defined,\n+\t#      so just omit it for testing purposes.\n+\t#\n+\t#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's\n+\t#      sake, skip it when parsing normal.\n+\tsed \\\n+\t\t-e 's/elapsed:[0-9]*\\.[0-9][0-9]*\\([eE][-+]\\{0,1\\}[0-9][0-9]*\\)\\{0,1\\}/elapsed:_TIME_/g' \\\n+\t\t-e \"s/^start '[^']*' \\(.*\\)/start _EXE_ \\1/\" \\\n+\t\t-e 's/^start [^ ][^ ]* \\(.*\\)/start _EXE_ \\1/' \\\n+\t\t-e '/^cmd_path/d' \\\n+\t\t-e '/^cmd_ancestry/d'\n+}\n+\n test_expect_success 'normal stream, return code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '\n test_expect_success 'normal stream, return code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 1\n@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '\n \ttest_when_finished \"rm -r traces actual expect\" &&\n \tmkdir traces &&\n \tGIT_TRACE2=\"$(pwd)/traces\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <\"$(ls traces/*)\" >actual &&\n+\tscrub_normal <\"$(ls traces/*)\" >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '\n test_expect_success 'normal stream, exit code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 0\n@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '\n test_expect_success 'normal stream, exit code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 1\n@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '\n test_expect_success 'normal stream, error event' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 003error \"hello world\" \"this is a test\" &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 003error '\\''hello world'\\'' '\\''this is a test'\\''\n@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '\n test_expect_success 'BUG messages are written to trace2' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 007bug &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 007bug\n@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 008bug\n@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 009bug_BUG\n@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 010bug_BUG\n@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '\n \ttest_config_global trace2.normalBrief 1 &&\n \ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '\n \tmv \"$(pwd)/.gitconfig\" \"$(pwd)/real.gitconfig\" &&\n \ttest_config_global include.path \"$(pwd)/real.gitconfig\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\ndiff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl\ndeleted file mode 100644\nindex 7cc4de392a0..00000000000\n--- a/t/t0210/scrub_normal.perl\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-#!/usr/bin/perl\n-#\n-# Scrub the variable fields from the normal trace2 output to\n-# make testing easier.\n-\n-use strict;\n-use warnings;\n-\n-my $float = '[0-9]*\\.[0-9]+([eE][-+]?[0-9]+)?';\n-\n-# This code assumes that the trace2 data was written with bare\n-# turned on (which omits the \"<clock> <file>:<line>\" prefix.\n-\n-while (<>) {\n-    # Various messages include an elapsed time in the middle\n-    # of the message.  Replace the time with a placeholder to\n-    # simplify our HEREDOC in the test script.\n-    s/elapsed:$float/elapsed:_TIME_/g;\n-\n-    my $line = $_;\n-\n-    # we expect:\n-    #    start <argv0> [<argv1> [<argv2> [...]]]\n-    #\n-    # where argv0 might be a relative or absolute path, with\n-    # or without quotes, and platform dependent.  Replace argv0\n-    # with a token for HEREDOC matching in the test script.\n-\n-    if ($line =~ m/^start/) {\n-\t$line =~ /^start\\s+(.*)/;\n-\tmy $argv = $1;\n-\t$argv =~ m/(\\'[^\\']*\\'|[^ ]+)\\s+(.*)/;\n-\tmy $argv_0 = $1;\n-\tmy $argv_rest = $2;\n-\n-\tprint \"start _EXE_ $argv_rest\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_path/) {\n-\t# Likewise, the 'cmd_path' message breaks out argv[0].\n-\t#\n-\t# This line is only emitted when RUNTIME_PREFIX is defined,\n-\t# so just omit it for testing purposes.\n-\t# print \"cmd_path _EXE_\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_ancestry/) {\n-\t# 'cmd_ancestry' is not implemented everywhere, so for portability's\n-\t# sake, skip it when parsing normal.\n-\t#\n-\t# print \"$line\";\n-    }\n-    else {\n-\tprint \"$line\";\n-    }\n-}\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515018","messageId":"20250325-b4-pks-t-perlless-v2-19-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 19/20] t5316: refactor `max_chain()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:37Z","receivedAt":"2025-03-25T13:14:44Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `max_chain()` helper function is used to extract the maximum delta\nchain of a packfile as printed by git-index-pack(1). The script uses\nPerl to extract that data, but it can be trivially refactored to use\nawk(1) instead.\n\nRefactor the helper accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5316-pack-delta-depth.sh | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex cd947b5a5ef..defaa06d650 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '\n \n max_chain() {\n \tgit index-pack --verify-stat-only \"$1\" >output &&\n-\tperl -lne '\n-\t  BEGIN { $len = 0 }\n-\t  /chain length = (\\d+)/ and $len = $1;\n-\t  END { print $len }\n-\t' output\n+\tawk '\n+\t\tBEGIN { len=0 }\n+\t\t/chain length = [0-9]+:/{ len=$4 }\n+\t\tEND { print len }\n+\t' <output | tr -d ':'\n }\n \n # Note that this whole setup is pretty reliant on the current\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n+test_expect_success 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n+test_expect_success '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n+test_expect_success '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n+test_expect_success 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515019","messageId":"20250325-b4-pks-t-perlless-v2-20-4b87b8072670@pks.im","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im","subject":"[PATCH v2 20/20] t5703: refactor test to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-25T13:14:38Z","receivedAt":"2025-03-25T13:14:45Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We use Perl due to two different reasons in t5703:\n\n  - To filter advertised capabilities.\n\n  - To set up a CGI script with HTTPD.\n\nRefactor the first category to use `test_grep` instead. Refactoring the\nsecond category would be a bit more involved, so instead we add the\nPERL_TEST_HELPERS prerequisite to those individual tests now.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------\n 1 file changed, 8 insertions(+), 17 deletions(-)\n\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex ac7266126a0..1ab3191d72d 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n-\ttest_done\n-fi\n-\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\n@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '\n \n test_expect_success 'config controls ref-in-want advertisement' '\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant false &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant true &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_file_not_empty out.filter\n+\ttest_grep \"ref-in-want\" out\n '\n \n test_expect_success 'invalid want-ref line' '\n@@ -486,7 +477,7 @@ inconsistency () {\n \tEOF\n }\n \n-test_expect_success 'server is initially ahead - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '\n \ttest_grep \"fatal: remote error: upload-pack: not our ref\" err\n '\n \n-test_expect_success 'server is initially ahead - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server loses a ref - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515025","messageId":"198d1d40-ea1f-4362-821c-2cc621892e4e@gmail.com","threadId":"63168","inReplyTo":"20250325-b4-pks-t-perlless-v2-11-4b87b8072670@pks.im","subject":"Re: [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-03-25T14:35:52Z","receivedAt":"2025-03-25T14:35:57Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Patrick\n\nOn 25/03/2025 13:14, Patrick Steinhardt wrote:\n>   broken_c_unquote () {\n> -\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n> +\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n>   }\n>   \n>   broken_c_unquote_verbose () {\n> -\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n> +\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n>   }\n\nThanks for removing the redirection here, unfortunately there are still \na whole bunch of needless input redirections below.\n\nBest Wishes\n\nPhillip\n\n>   stderr_contains () {\n> diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\n> index a92a42990b1..db75998e35f 100755\n> --- a/t/t4029-diff-trailing-space.sh\n> +++ b/t/t4029-diff-trailing-space.sh\n> @@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n>   EOF\n>   exit 1\n>   \n> -test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n> +test_expect_success \"$test_description\" '\n>   \tprintf \"\\nx\\n\" > f &&\n>   \tbefore=$(git hash-object f) &&\n>   \tbefore=$(git rev-parse --short $before) &&\n> @@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n>   \tgit config --bool diff.suppressBlankEmpty true &&\n>   \tgit diff f > actual &&\n>   \ttest_cmp exp actual &&\n> -\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n> +\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n\n> +\tmv exp.munged exp &&\n>   \tgit config --bool diff.suppressBlankEmpty false &&\n>   \tgit diff f > actual &&\n>   \ttest_cmp exp actual &&\n> diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\n> index 7fcca9ddad5..bacb93d014f 100755\n> --- a/t/t4200-rerere.sh\n> +++ b/t/t4200-rerere.sh\n> @@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping rerere tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   test_expect_success 'setup' '\n>   \tcat >a1 <<-\\EOF &&\n>   \tSome title\n> @@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n>   \ttest_might_fail git config --unset rerere.enabled &&\n>   \ttest_must_fail git merge first &&\n>   \n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1 &&\n>   \tgrep \"^=======\\$\" $rr/preimage &&\n>   \t! test -f $rr/postimage &&\n> @@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n>   \tgit reset --hard &&\n>   \ttest_must_fail git merge first &&\n>   \n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1 &&\n>   \tgrep ^=======$ $rr/preimage\n>   '\n> @@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n>   \tgit config rerere.enabled true &&\n>   \tgit reset --hard &&\n>   \ttest_must_fail git merge first &&\n> -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n> +\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>   \trr=.git/rr-cache/$sha1\n>   '\n>   \n> diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\n> index ac5e370e1e4..07382797bbb 100755\n> --- a/t/t5303-pack-corruption-resilience.sh\n> +++ b/t/t5303-pack-corruption-resilience.sh\n> @@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n>   \tgit cat-file blob $blob_3 > /dev/null\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n> +test_expect_success 'create corruption in data of first object' '\n>   \tcreate_new_pack &&\n>   \tgit prune-packed &&\n>   \tchmod +w ${pack}.pack &&\n> -\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n> +\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n> +\tmv ${pack}.pack.munged ${pack}.pack &&\n>   \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n> @@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n>   \tgit cat-file blob $blob_3 > /dev/null\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n> +test_expect_success 'create corruption in data of first delta' '\n>   \tcreate_new_pack &&\n>   \tgit prune-packed &&\n>   \tchmod +w ${pack}.pack &&\n> -\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n> +\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n> +\tmv ${pack}.pack.munged ${pack}.pack &&\n>   \tgit cat-file blob $blob_1 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>   \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n> diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\n> index 81987296235..9033d72b8c7 100755\n> --- a/t/t5310-pack-bitmaps.sh\n> +++ b/t/t5310-pack-bitmaps.sh\n> @@ -395,7 +395,7 @@ test_bitmap_cases () {\n>   \t\t)\n>   \t'\n>   \n> -\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n> +\ttest_expect_success 'pack.preferBitmapTips' '\n>   \t\tgit init repo &&\n>   \t\ttest_when_finished \"rm -fr repo\" &&\n>   \t\t(\n> @@ -421,7 +421,7 @@ test_bitmap_cases () {\n>   \n>   \t\t\t# mark the commits which did not receive bitmaps as preferred,\n>   \t\t\t# and generate the bitmap again\n> -\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n> +\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n>   \t\t\t\tgit update-ref --stdin &&\n>   \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n>   \n> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\n> index 342d0423c92..d5c0d00114e 100755\n> --- a/t/t5534-push-signed.sh\n> +++ b/t/t5534-push-signed.sh\n> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n>   \ttest_cmp expect dst/push-cert-status\n>   '\n>   \n> -test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n> +test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n>   \t# First, invoke receive-pack with dummy input to obtain its preamble.\n>   \tprepare_dst &&\n>   \tgit -C dst config receive.certnonceseed sekrit &&\n> @@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n>   \t# Tweak the push output to make the push option outside the cert\n>   \t# different, then replay it on a fresh dst, checking that ff is not\n>   \t# deleted.\n> -\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n> +\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n>   \tprepare_dst &&\n>   \tgit -C dst config receive.certnonceseed sekrit &&\n>   \tgit -C dst config receive.advertisepushoptions 1 &&\n> diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\n> index 6131c361094..12329aab388 100755\n> --- a/t/t6011-rev-list-with-bad-commit.sh\n> +++ b/t/t6011-rev-list-with-bad-commit.sh\n> @@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   # Note:\n>   # - compression level is set to zero to make \"corruptions\" easier to perform\n>   # - reflog is disabled to avoid extra references which would twart the test\n> @@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n>      first_commit=$(git rev-parse HEAD~3)\n>      '\n>   \n> -test_expect_success 'corrupt second commit object' \\\n> -   '\n> -   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n> -   test_must_fail git fsck --full\n> -   '\n> +test_expect_success 'corrupt second commit object' '\n> +\tfor p in .git/objects/pack/*.pack\n> +\tdo\n> +\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n> +\t\tmv \"$p.munged\" \"$p\" ||\n> +\t\treturn 1\n> +\tdone &&\n> +\ttest_must_fail git fsck --full\n> +'\n>   \n>   test_expect_success 'rev-list should fail' '\n>   \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\n> diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\n> index 14069600a2f..00b81d349b9 100755\n> --- a/t/t7416-submodule-dash-url.sh\n> +++ b/t/t7416-submodule-dash-url.sh\n> @@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping submodule dash URL tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   test_expect_success 'setup' '\n>   \tgit config --global protocol.file.allow always\n>   '\n> @@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n>   '\n>   \n>   test_expect_success 'remove ./ protection from .gitmodules url' '\n> -\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n> +\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n> +\tmv .gitmodules.munged .gitmodules &&\n>   \tgit commit -am \"drop protection\"\n>   '\n>   \n> diff --git a/t/t7508-status.sh b/t/t7508-status.sh\n> index 14c41b2cb7c..cdc1d6fcc78 100755\n> --- a/t/t7508-status.sh\n> +++ b/t/t7508-status.sh\n> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n>   \ttest_cmp expect output\n>   '\n>   \n> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n> +test_expect_success 'status -z implies porcelain' '\n>   \tgit status --porcelain |\n> -\tperl -pe \"s/\\012/\\000/g\" >expect &&\n> +\ttr \"\\012\" \"\\000\" >expect &&\n>   \tgit status -z >output &&\n>   \ttest_cmp expect output\n>   '\n> diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\n> index 5cb16872081..810dac18f56 100755\n> --- a/t/t8006-blame-textconv.sh\n> +++ b/t/t8006-blame-textconv.sh\n> @@ -4,12 +4,6 @@ test_description='git blame textconv support'\n>   \n>   . ./test-lib.sh\n>   \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping blame textconv tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>   find_blame() {\n>   \tsed -e 's/^[^(]*//'\n>   }\n> @@ -17,7 +11,7 @@ find_blame() {\n>   cat >helper <<'EOF'\n>   #!/bin/sh\n>   grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n> -\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n> +sed 's/^bin: /converted: /' <\"$1\"\n>   EOF\n>   chmod +x helper\n>   \n> diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\n> index a9d38be997c..9afdb45b1cc 100755\n> --- a/t/t9137-git-svn-dcommit-clobber-series.sh\n> +++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n> @@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n>   \ttest -e file\n>   \t'\n>   \n> -test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n> +test_expect_success '(supposedly) non-conflicting change from SVN' '\n>   \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n>   \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n>   \tsvn_cmd co \"$svnrepo\" tmp &&\n>   \t(cd tmp &&\n> -\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n> -\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n> +\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n> +\t\tmv file.munged file &&\n>   \t\tpoke file &&\n>   \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n>   \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n> @@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n>   \tgit commit -m bye-life life\n>   \t\"\n>   \n> -test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n> +test_expect_success 'change file but in unrelated area' \"\n>   \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n>   \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n> -\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n> -\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n> +\tsed -e 's/^4\\$/4444/' \\\n> +\t    -e 's/^7\\$/7777/' \\\n> +\t\t<file >file.munged &&\n> +\tmv file.munged file &&\n>   \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n>   \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n>   \tgit commit -m '4 => 4444, 7 => 7777' file &&\n> \n\n"},{"id":"515147","messageId":"Z-UmLWcMgW2f9970@pks.im","threadId":"63168","inReplyTo":"198d1d40-ea1f-4362-821c-2cc621892e4e@gmail.com","subject":"Re: [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:19:25Z","receivedAt":"2025-03-27T10:19:31Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Mar 25, 2025 at 02:35:52PM +0000, Phillip Wood wrote:\n> Hi Patrick\n> \n> On 25/03/2025 13:14, Patrick Steinhardt wrote:\n> >   broken_c_unquote () {\n> > -\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n> > +\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n> >   }\n> >   broken_c_unquote_verbose () {\n> > -\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n> > +\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n> >   }\n> \n> Thanks for removing the redirection here, unfortunately there are still a\n> whole bunch of needless input redirections below.\n\nFair. I've scanned through all commits now and replaced every use of\nsuch redirects. Will send out that version soonish.\n\nPatrick\n"},{"id":"515149","messageId":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH v3 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:36:58Z","receivedAt":"2025-03-27T10:37:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nwhile Git was initially building on Perl quite a lot, the significance\nof Perl has been dwindling over the years as more and more functionality\nwas converted into C builtins. Nowadays, an installation with Perl-based\nfeatures disabled is almost fully functional, only a handful of features\nremain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these features really are critical for day-to-day usage of Git,\nand most users probably wouldn't even notice if those features were not\ninstalled. Perl is thus very much optional nowadays.\n\nThere is one big exception though: it is impossible to run our test\nsuite without a Perl interpreter, so it is not easily possible to verify\nthat a Perl-less installation actually works as expected. For most of\nthe part though our test suite doesn't use all that much Perl, either.\nIt is present in a couple of critical paths, but those are easy to adapt\nto not use Perl anymore.\n\nThis is exactly what this patch series does: it refactors a couple of\ncentral parts in our test suite to not use Perl anymore so that it\nbecomes possible to run most of our tests entirely without Perl. Tests\nthat still depend on Perl are marked with a new PERL_TEST_HELPERS prereq\nso that they only execute when a Perl interpreter is available.\n\nWith this patch series, 30342 out of 31358 tests pass, which is around\n97% of our tests.\n\nChanges in v2:\n  - Improve a couple of conversions based on feedback.\n  - Clarify the commit message of the textconv conversion.\n  - Fix a copy-paste error when it comes to skipping tests in t4103.\n  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im\n\nChanges in v3:\n  - Remove more useless indirections for sed(1).\n  - Link to v2: https://lore.kernel.org/r/20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (20):\n      t: skip chain lint when PERL_PATH is unset\n      t: refactor environment sanitization to not use Perl\n      t: adapt character translation helpers to not use Perl\n      t: adapt `test_copy_bytes()` to not use Perl\n      t: adapt `test_readlink()` to not use Perl\n      t: introduce PERL_TEST_HELPERS prerequisite\n      t: adapt existing PERL prerequisites\n      meson: stop requiring Perl when tests are enabled\n      Makefile: stop requiring Perl when running tests\n      t: refactor tests depending on Perl transliteration operator\n      t: refactor tests depending on Perl substitution operator\n      t: refactor tests depending on Perl to print data\n      t: refactor tests depending on Perl for textconv scripts\n      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n      t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n      t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n      t0021: refactor `generate_random_characters()` to not depend on Perl\n      t0210: refactor trace2 scrubbing to not use Perl\n      t5316: refactor `max_chain()` to not depend on Perl\n      t5703: refactor test to not depend on Perl\n\n meson.build                               |  2 +-\n t/Makefile                                | 16 +++++++--\n t/helper/test-path-utils.c                | 13 ++++++++\n t/helper/test-sha1.sh                     |  4 +--\n t/lib-diff.sh                             |  4 +--\n t/lib-gpg.sh                              |  6 +---\n t/lib-httpd.sh                            |  2 +-\n t/lib-httpd/apache.conf                   |  6 ++--\n t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------\n t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++\n t/lib-t6000.sh                            | 13 ++++----\n t/t0008-ignores.sh                        |  4 +--\n t/t0021-conversion.sh                     | 13 ++++----\n t/t0090-cache-tree.sh                     |  4 +--\n t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------\n t/t0210/scrub_normal.perl                 | 54 ------------------------------\n t/t0211-trace2-perf.sh                    |  6 ++++\n t/t0610-reftable-basics.sh                |  5 ++-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       | 16 +++++----\n t/t1007-hash-object.sh                    |  6 ++--\n t/t1010-mktree.sh                         |  4 +--\n t/t1450-fsck.sh                           |  6 ++--\n t/t3300-funny-names.sh                    |  6 ++--\n t/t4013-diff-various.sh                   |  6 ++++\n t/t4014-format-patch.sh                   | 30 ++++++++---------\n t/t4020-diff-external.sh                  |  2 +-\n t/t4029-diff-trailing-space.sh            |  3 +-\n t/t4030-diff-textconv.sh                  |  9 ++---\n t/t4031-diff-rewrite-binary.sh            | 17 ++++------\n t/t4058-diff-duplicates.sh                |  6 ++++\n t/t4103-apply-binary.sh                   |  6 ++--\n t/t4116-apply-reverse.sh                  |  4 +--\n t/t4150-am.sh                             |  8 ++---\n t/t4200-rerere.sh                         |  8 ++---\n t/t4205-log-pretty-formats.sh             |  6 ++--\n t/t4216-log-bloom.sh                      |  8 ++---\n t/t5004-archive-corner-cases.sh           |  6 ++++\n t/t5300-pack-object.sh                    | 10 +++---\n t/t5303-pack-corruption-resilience.sh     |  6 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               | 10 +++---\n t/t5318-commit-graph.sh                   | 12 +++----\n t/t5319-multi-pack-index.sh               | 16 ++++-----\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  4 +--\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  2 +-\n t/t5503-tagfollow.sh                      |  6 ++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++\n t/t5532-fetch-proxy.sh                    |  6 ++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  | 15 ++++-----\n t/t5551-http-fetch-smart.sh               |  7 ++++\n t/t5562-http-backend-content-length.sh    |  6 ++++\n t/t5601-clone.sh                          |  4 +--\n t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------\n t/t5701-git-serve.sh                      |  5 ++-\n t/t5702-protocol-v2.sh                    | 21 +++++++-----\n t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------\n t/t5710-promisor-remote-capability.sh     |  6 ++++\n t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---\n t/t6013-rev-list-reverse-parents.sh       | 10 +++---\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++\n t/t6115-rev-list-du.sh                    |  2 +-\n t/t6300-for-each-ref.sh                   | 15 ++++++---\n t/t7006-pager.sh                          |  6 ++--\n t/t7416-submodule-dash-url.sh             |  3 +-\n t/t7501-commit-basic-functionality.sh     |  6 ++--\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  9 ++---\n t/t8001-annotate.sh                       |  6 ++++\n t/t8002-blame.sh                          |  8 ++++-\n t/t8006-blame-textconv.sh                 |  2 +-\n t/t8011-blame-split-file.sh               |  6 ++--\n t/t8012-blame-colors.sh                   |  6 ++++\n t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib-functions.sh                   | 20 +++--------\n t/test-lib.sh                             | 49 +++++++++++++++++----------\n 84 files changed, 471 insertions(+), 373 deletions(-)\n\nRange-diff versus v2:\n\n 1:  8c98b24fe4c =  1:  f2fe08ef0ff t: skip chain lint when PERL_PATH is unset\n 2:  f140153954c =  2:  9dd2edd0a1a t: refactor environment sanitization to not use Perl\n 3:  94b5591f666 =  3:  c77424e6907 t: adapt character translation helpers to not use Perl\n 4:  a5880fdb8ef =  4:  476d1b15932 t: adapt `test_copy_bytes()` to not use Perl\n 5:  3b64c99c061 =  5:  14badee2551 t: adapt `test_readlink()` to not use Perl\n 6:  a3536260e4c =  6:  9a88a46bd10 t: introduce PERL_TEST_HELPERS prerequisite\n 7:  98961b0e065 =  7:  e7413bf28ae t: adapt existing PERL prerequisites\n 8:  bbdd1fe6c7c =  8:  581a9bedd22 meson: stop requiring Perl when tests are enabled\n 9:  bda7e7922ce =  9:  cfe1797ae74 Makefile: stop requiring Perl when running tests\n10:  d95d50c4b73 = 10:  99e678b83a6 t: refactor tests depending on Perl transliteration operator\n11:  f5b30cc3f8f ! 11:  93a98d3e3cf t: refactor tests depending on Perl substitution operator\n    @@ t/t4029-diff-trailing-space.sh: test_expect_success PERL_TEST_HELPERS \"$test_des\n      \tgit diff f > actual &&\n      \ttest_cmp exp actual &&\n     -\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n    -+\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n    ++\tsed \"s/^\\$/ /\" exp >exp.munged &&\n     +\tmv exp.munged exp &&\n      \tgit config --bool diff.suppressBlankEmpty false &&\n      \tgit diff f > actual &&\n    @@ t/t4200-rerere.sh: test_expect_success 'activate rerere, old style (conflicting\n      \ttest_must_fail git merge first &&\n      \n     -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n    -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n    ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n      \trr=.git/rr-cache/$sha1 &&\n      \tgrep \"^=======\\$\" $rr/preimage &&\n      \t! test -f $rr/postimage &&\n    @@ t/t4200-rerere.sh: test_expect_success 'rerere.enabled works, too' '\n      \ttest_must_fail git merge first &&\n      \n     -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n    -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n    ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n      \trr=.git/rr-cache/$sha1 &&\n      \tgrep ^=======$ $rr/preimage\n      '\n    @@ t/t4200-rerere.sh: test_expect_success 'set up rr-cache' '\n      \tgit reset --hard &&\n      \ttest_must_fail git merge first &&\n     -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n    -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n    ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n      \trr=.git/rr-cache/$sha1\n      '\n      \n    @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and loose copy o\n      \tgit prune-packed &&\n      \tchmod +w ${pack}.pack &&\n     -\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n    -+\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n    ++\tsed \"s/ base /abcdef/\" ${pack}.pack >${pack}.pack.munged &&\n     +\tmv ${pack}.pack.munged ${pack}.pack &&\n      \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n      \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n    @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and then a repac\n      \tgit prune-packed &&\n      \tchmod +w ${pack}.pack &&\n     -\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n    -+\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n    ++\tsed \"s/ delta1 /abcdefgh/\" ${pack}.pack >${pack}.pack.munged &&\n     +\tmv ${pack}.pack.munged ${pack}.pack &&\n      \tgit cat-file blob $blob_1 > /dev/null &&\n      \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n    @@ t/t5310-pack-bitmaps.sh: test_bitmap_cases () {\n      \t\t\t# mark the commits which did not receive bitmaps as preferred,\n      \t\t\t# and generate the bitmap again\n     -\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n    -+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n    ++\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n      \t\t\t\tgit update-ref --stdin &&\n      \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n      \n    @@ t/t5534-push-signed.sh: test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent\n      \t# different, then replay it on a fresh dst, checking that ff is not\n      \t# deleted.\n     -\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n    -+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n    ++\tsed \"s/\\([^ ]\\)bar/\\1baz/\" push >push.tweak &&\n      \tprepare_dst &&\n      \tgit -C dst config receive.certnonceseed sekrit &&\n      \tgit -C dst config receive.advertisepushoptions 1 &&\n    @@ t/t6011-rev-list-with-bad-commit.sh: test_expect_success 'verify number of revis\n     +test_expect_success 'corrupt second commit object' '\n     +\tfor p in .git/objects/pack/*.pack\n     +\tdo\n    -+\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n    ++\t\tsed \"s/second commit/socond commit/\" \"$p\" >\"$p.munged\" &&\n     +\t\tmv \"$p.munged\" \"$p\" ||\n     +\t\treturn 1\n     +\tdone &&\n    @@ t/t7416-submodule-dash-url.sh: test_expect_success 'fsck accepts protected dash'\n      \n      test_expect_success 'remove ./ protection from .gitmodules url' '\n     -\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n    -+\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n    ++\tsed \"s|\\./||\" .gitmodules >.gitmodules.munged &&\n     +\tmv .gitmodules.munged .gitmodules &&\n      \tgit commit -am \"drop protection\"\n      '\n    @@ t/t8006-blame-textconv.sh: find_blame() {\n      #!/bin/sh\n      grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n     -\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n    -+sed 's/^bin: /converted: /' <\"$1\"\n    ++sed 's/^bin: /converted: /' \"$1\"\n      EOF\n      chmod +x helper\n      \n    @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'initialize repo'\n      \t(cd tmp &&\n     -\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n     -\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n    -+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n    ++\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" file >file.munged &&\n     +\t\tmv file.munged file &&\n      \t\tpoke file &&\n      \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n    @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'some unrelated c\n     -\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n     +\tsed -e 's/^4\\$/4444/' \\\n     +\t    -e 's/^7\\$/7777/' \\\n    -+\t\t<file >file.munged &&\n    ++\t\tfile >file.munged &&\n     +\tmv file.munged file &&\n      \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n      \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n12:  e978d8ecfde ! 12:  17f862eaba3 t: refactor tests depending on Perl to print data\n    @@ t/t5300-pack-object.sh: test_expect_success 'pack-object <stdin parsing: --stdin\n      # e.g.: check_deltas stderr -gt 0\n      check_deltas() {\n     -\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n    -+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' <\"$1\") &&\n    ++\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' \"$1\") &&\n      \tshift &&\n      \tif ! test \"$deltas\" \"$@\"\n      \tthen\n    @@ t/t5326-multi-pack-bitmaps.sh: test_midx_bitmap_cases () {\n      \n     -\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n     -\t\t\t\t<before | git update-ref --stdin &&\n    -+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n    ++\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n     +\t\t\tgit update-ref --stdin &&\n      \n      \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n    @@ t/t5333-pseudo-merge-bitmaps.sh: test_pseudo_merges_reused () {\n     -\tperl -lne '\n     -\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n     -\t' <in | git update-ref --stdin\n    -+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' <in |\n    ++\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' in |\n     +\tgit update-ref --stdin\n      }\n      \n    @@ t/t5333-pseudo-merge-bitmaps.sh: test_expect_success 'pseudo-merge pattern with\n      \t\t\tgit rev-list HEAD~16.. >in &&\n     -\n     -\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n    -+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" <in |\n    ++\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n      \t\t\tgit update-ref --stdin || return 1\n      \t\tdone &&\n      \n    @@ t/t8002-blame.sh: test_expect_success 'set up abbrev tests' '\n      \t\techo $sha1 | cut -c 1-$expect >expect &&\n      \t\tgit blame \"$@\" abbrev.t >actual &&\n     -\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n    -+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" <actual >actual.sha &&\n    ++\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" actual >actual.sha &&\n      \t\ttest_cmp expect actual.sha\n      \t}\n      '\n13:  905c25c9fb2 = 13:  7b03d096ccd t: refactor tests depending on Perl for textconv scripts\n14:  1fe67bba30f = 14:  195c0bf2445 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n15:  9e572c3ba67 = 15:  e92d178b96b t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n16:  24abcffe96e ! 16:  0f2c9ad276b t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n    @@ t/t5537-fetch-shallow.sh: test_expect_success PERL_TEST_HELPERS 'shallow fetches\n     -\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n     -\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n    -+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" <\"\\$1\"\n    ++\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" \"\\$1\"\n     +\tEOF\n      \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n     -\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n    @@ t/t5616-partial-clone.sh: intersperse () {\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n     +\tif grep packfile \"\\$1\" >/dev/null\n     +\tthen\n    -+\t\tsed '/packfile/q' <\"\\$1\" &&\n    ++\t\tsed '/packfile/q' \"\\$1\" &&\n     +\t\t# The protocol requires that the packfile be sent in sideband\n     +\t\t# 1, hence the extra \\001 byte at the beginning.\n     +\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n    @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server sends\n     -\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n     -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n    -+\tsed \"/ready/{n;s/0001/0000/;}\" <\"$1\"\n    ++\tsed \"/ready/{n;s/0001/0000/;}\" \"$1\"\n     +\tEOF\n      \n      \ttest_must_fail git -C http_child -c protocol.version=2 \\\n    @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server does\n     -\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n     -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n    -+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" <\"$1\"\n    ++\tsed \"/acknowledgments/,//{s/0000/0001/;}\" \"$1\"\n     +\tEOF\n      \n      \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n    @@ t/t5702-protocol-v2.sh: test_expect_success 'http:// --negotiate-only' '\n     -\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n     -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n    -+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" <\"$1\"\n    ++\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \"$1\"\n     +\tEOF\n      \n      \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n    @@ t/t5703-upload-pack-ref-in-want.sh: inconsistency () {\n      \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n     -\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n    -+\tsed \"s/$oid1/$oid2/\" <\"\\$1\"\n    ++\tsed \"s/$oid1/$oid2/\" \"\\$1\"\n     +\tEOF\n      }\n      \n    @@ t/t5703-upload-pack-ref-in-want.sh: test_expect_success 'server loses a ref - re\n      \tcp -r \"$LOCAL_PRISTINE\" local &&\n     -\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n     +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n    -+\tsed \"s/main/rain/\" <\"$1\"\n    ++\tsed \"s/main/rain/\" \"$1\"\n     +\tEOF\n      \ttest_must_fail git -C local fetch 2>err &&\n      \n17:  ce5adbd4818 = 17:  9857b461ed6 t0021: refactor `generate_random_characters()` to not depend on Perl\n18:  e183c397da9 = 18:  7924b5bd9bf t0210: refactor trace2 scrubbing to not use Perl\n19:  156bdc4d62d = 19:  5d6996a1412 t5316: refactor `max_chain()` to not depend on Perl\n20:  3b181d0a203 = 20:  0c3afb70128 t5703: refactor test to not depend on Perl\n\n---\nbase-commit: 683c54c999c301c2cd6f715c411407c413b1d84e\nchange-id: 20250317-b4-pks-t-perlless-138cf94696b8\n\n"},{"id":"515150","messageId":"20250327-b4-pks-t-perlless-v3-1-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:36:59Z","receivedAt":"2025-03-27T10:37:11Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our chainlint script verifies that test files have proper '&&' chains.\nThis script is written in Perl and executed for every test file before\nexecuting the test logic itself.\n\nIn subsequent commits we're about to refactor our test suite so that\nPerl becomes an optional dependency, only. And while it is already\npossible to disable this linter, developers that don't have Perl\navailable at all would always have to disable the linter manually, which\nis rather cumbersome.\n\nDisable the chain linter automatically in case PERL_PATH isn't set to\nmake this a bit less annoying. Bail out with an error in case the\ndeveloper has asked explicitly for the chain linter.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..1ce3b32fcac 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1523,6 +1523,22 @@ then\n \texport LSAN_OPTIONS\n fi\n \n+if test -z \"$PERL_PATH\"\n+then\n+\tcase \"${GIT_TEST_CHAIN_LINT:-unset}\" in\n+\tunset)\n+\t\tGIT_TEST_CHAIN_LINT=0\n+\t\t;;\n+\t0)\n+\t\t# The user has explicitly disabled the chain linter, so we\n+\t\t# don't have anything to worry about.\n+\t\t;;\n+\t*)\n+\t\tBAIL_OUT 'You need Perl for the chain linter'\n+\t\t;;\n+\tesac\n+fi\n+\n if test \"${GIT_TEST_CHAIN_LINT:-1}\" != 0 &&\n    test \"${GIT_TEST_EXT_CHAIN_LINT:-1}\" != 0\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515151","messageId":"20250327-b4-pks-t-perlless-v3-3-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 03/20] t: adapt character translation helpers to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:01Z","receivedAt":"2025-03-27T10:37:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of helper functions that translate characters, e.g.\nfrom LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl\nscripts, but they can be trivially adapted to instead use tr(1).\n\nNote that one specialty here is the handling of NUL characters in tr(1),\nwhich historically wasn't implemented correctly on all platforms. But\nquoting tr(1p):\n\n    It was considered that automatically stripping NUL characters from\n    the input was not correct functionality.  However, the removal of -n\n    in a later proposal does not remove the requirement that tr\n    correctly process NUL characters in its input stream.\n\nSo when tr(1) is implemented following the POSIX standard then it is\nexpected to handle the transliteration of NUL just fine.\n\nRefactor the helpers accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 79377bc0fc2..377f08a1428 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -88,15 +88,15 @@ test_decode_color () {\n }\n \n lf_to_nul () {\n-\tperl -pe 'y/\\012/\\000/'\n+\ttr '\\012' '\\000'\n }\n \n nul_to_q () {\n-\tperl -pe 'y/\\000/Q/'\n+\ttr '\\000' 'Q'\n }\n \n q_to_nul () {\n-\tperl -pe 'y/Q/\\000/'\n+\ttr 'Q' '\\000'\n }\n \n q_to_cr () {\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515152","messageId":"20250327-b4-pks-t-perlless-v3-2-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 02/20] t: refactor environment sanitization to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:00Z","receivedAt":"2025-03-27T10:37:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Before executing tests we first sanitize the environment. Part of the\nsanitization is to unset a couple of environment variables that we know\nwill change the behaviour of Git. This is done with a small Perl script,\nwhich has the consequence that having a Perl interpreter available is a\nstrict requirement for running our unit tests.\n\nThe logic itself isn't particularly involved: we simply unset every\nenvironment variable whose key starts with 'GIT_', but then explicitly\nallow a subset of these.\n\nRefactor the logic to instead use sed(1) so that it becomes possible to\nexecute our tests without Perl.\n\nBased-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 32 ++++++++++++++------------------\n 1 file changed, 14 insertions(+), 18 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 1ce3b32fcac..a62699d6c79 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -499,24 +499,20 @@ EDITOR=:\n # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets\n # deriving from the command substitution clustered with the other\n # ones.\n-unset VISUAL EMAIL LANGUAGE $(\"$PERL_PATH\" -e '\n-\tmy @env = keys %ENV;\n-\tmy $ok = join(\"|\", qw(\n-\t\tTRACE\n-\t\tDEBUG\n-\t\tTEST\n-\t\t.*_TEST\n-\t\tPROVE\n-\t\tVALGRIND\n-\t\tUNZIP\n-\t\tPERF_\n-\t\tCURL_VERBOSE\n-\t\tTRACE_CURL\n-\t\tBUILD_DIR\n-\t));\n-\tmy @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);\n-\tprint join(\"\\n\", @vars);\n-')\n+unset VISUAL EMAIL LANGUAGE $(env | sed -n \\\n+\t-e '/^GIT_TRACE/d' \\\n+\t-e '/^GIT_DEBUG/d' \\\n+\t-e '/^GIT_TEST/d' \\\n+\t-e '/^GIT_.*_TEST/d' \\\n+\t-e '/^GIT_PROVE/d' \\\n+\t-e '/^GIT_VALGRIND/d' \\\n+\t-e '/^GIT_UNZIP/d' \\\n+\t-e '/^GIT_PERF_/d' \\\n+\t-e '/^GIT_CURL_VERBOSE/d' \\\n+\t-e '/^GIT_TRACE_CURL/d' \\\n+\t-e '/^GIT_BUILD_DIR/d' \\\n+\t-e 's/^\\(GIT_[^=]*\\)=.*/\\1/p'\n+)\n unset XDG_CACHE_HOME\n unset XDG_CONFIG_HOME\n unset GITPERLLIB\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515153","messageId":"20250327-b4-pks-t-perlless-v3-4-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 04/20] t: adapt `test_copy_bytes()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:02Z","receivedAt":"2025-03-27T10:37:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_copy_bytes()` helper function copies up to N bytes from stdin\nto stdout. This is implemented using Perl, but it can be trivially\nadapted to instead use dd(1).\n\nRefactor the helper accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 12 +-----------\n 1 file changed, 1 insertion(+), 11 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 377f08a1428..c4b4d3a4c7f 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1640,17 +1640,7 @@ test_match_signal () {\n \n # Read up to \"$1\" bytes (or to EOF) from stdin and write them to stdout.\n test_copy_bytes () {\n-\tperl -e '\n-\t\tmy $len = $ARGV[1];\n-\t\twhile ($len > 0) {\n-\t\t\tmy $s;\n-\t\t\tmy $nread = sysread(STDIN, $s, $len);\n-\t\t\tdie \"cannot read: $!\" unless defined($nread);\n-\t\t\tlast unless $nread;\n-\t\t\tprint $s;\n-\t\t\t$len -= $nread;\n-\t\t}\n-\t' - \"$1\"\n+\tdd ibs=1 count=\"$1\" 2>/dev/null\n }\n \n # run \"$@\" inside a non-git directory\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515154","messageId":"20250327-b4-pks-t-perlless-v3-5-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 05/20] t: adapt `test_readlink()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:03Z","receivedAt":"2025-03-27T10:37:14Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_readlink()` helper function reads a symbolic link and returns\nthe path it is pointing to. It is thus equivalent to the readlink(1)\nutility, which isn't available on all supported platforms. As such, it\nis implemented using Perl so that we can use it even on platforms where\nthe shell utility isn't available.\n\nWhile using readlink(1) is not an option, what we can do is to implement\nthe logic ourselves in our test-tool. Do so, which allows a bunch of\ntests to pass when Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-path-utils.c | 13 +++++++++++++\n t/test-lib-functions.sh    |  2 +-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 72ac8d1b1b0..54d9ba98c0e 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc >= 2 && !strcmp(argv[1], \"readlink\")) {\n+\t\tstruct strbuf target = STRBUF_INIT;\n+\t\twhile (argc > 2) {\n+\t\t\tif (strbuf_readlink(&target, argv[2], 0) < 0)\n+\t\t\t\tdie_errno(\"cannot read link at '%s'\", argv[2]);\n+\t\t\tputs(target.buf);\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t}\n+\t\tstrbuf_release(&target);\n+\t\treturn 0;\n+\t}\n+\n \tif (argc >= 2 && !strcmp(argv[1], \"absolute_path\")) {\n \t\twhile (argc > 2) {\n \t\t\tputs(absolute_path(argv[2]));\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex c4b4d3a4c7f..bff8c4d1b41 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1979,7 +1979,7 @@ test_remote_https_urls() {\n # Print the destination of symlink(s) provided as arguments. Basically\n # the same as the readlink command, but it's not available everywhere.\n test_readlink () {\n-\tperl -le 'print readlink($_) for @ARGV' \"$@\"\n+\ttest-tool path-utils readlink \"$@\"\n }\n \n # Set mtime to a fixed \"magic\" timestamp in mid February 2009, before we\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515155","messageId":"20250327-b4-pks-t-perlless-v3-7-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 07/20] t: adapt existing PERL prerequisites","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:05Z","receivedAt":"2025-03-27T10:37:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A couple of our tests depend on the PERL prerequisite even though it\nisn't needed. These tests fall into one of the following classes:\n\n  - The underlying logic used to be implemented in Perl but isn't\n    anymore. Here we can simply drop the dependency altogether.\n\n  - The test logic used to depend on Perl but doesn't anymore. Again, we\n    can simply drop the dependency.\n\n  - The test logic still relies on a Perl interpreter. These tests\n    should use the newly introduced PERL_TEST_HELPERS prerequisite.\n\nAdapt test cases accordingly.\n\nNote that in t1006 we have to introduce another new prerequisite\ndepending on whether or not the IPC::Open2 module is available. Funny\nenough, when starting to use `test_lazy_prereq` to do so we also get a\nconflict of variables with the \"script\" variable that contains the Perl\nlogic because `test_run_lazy_prereq_` also sets that variable. We thus\nrename the variable in t1006 to \"perl_script\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh                 | 10 +++++-----\n t/t0090-cache-tree.sh                 |  4 ++--\n t/t1006-cat-file.sh                   | 14 +++++++++-----\n t/t7501-commit-basic-functionality.sh |  6 +++---\n 4 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 9c3738ebb3f..4a892a91780 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'\n \t)\n '\n \n-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n+test_expect_success 'invalid process filter must fail (and not hang!)' '\n \ttest_config_global filter.protocol.process cat &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n@@ -1111,19 +1111,19 @@ do\n \tbranch) opt='-f HEAD' ;;\n \tesac\n \n-\ttest_expect_success PERL,TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress test_terminal git checkout $opt\n \t'\n \n-\ttest_expect_success PERL \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n+\ttest_expect_success \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! git checkout $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --quiet $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&\n \t\ttest_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt\n \t'\ndiff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh\nindex ab80c9ef135..d9015882946 100755\n--- a/t/t0090-cache-tree.sh\n+++ b/t/t0090-cache-tree.sh\n@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '\n \ttest_cache_tree\n '\n \n-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '\n+test_expect_success 'commit --interactive gives cache-tree on partial commit' '\n \ttest_when_finished \"git reset --hard\" &&\n \tcat <<-\\EOT >foo.c &&\n \tint foo()\n@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi\n \ttest_cache_tree expected.status\n '\n \n-test_expect_success PERL 'commit -p with shrinking cache-tree' '\n+test_expect_success 'commit -p with shrinking cache-tree' '\n \tmkdir -p deep/very-long-subdir &&\n \techo content >deep/very-long-subdir/file &&\n \tgit add deep &&\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex a574da3df53..0a22b0a7b8e 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '\n \tgrep \"^fatal:.*flush is only for --buffer mode.*\" err\n '\n \n-script='\n+perl_script='\n use warnings;\n use strict;\n use IPC::Open2;\n@@ -1345,12 +1345,16 @@ $? == 0 or die \"\\$?=$?\";\n \n expect=\"$hello_oid blob $hello_size\"\n \n-test_expect_success PERL '--batch-check is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-check $hello_oid \"$expect\"\n+test_lazy_prereq PERL_IPC_OPEN2 '\n+\tperl -MIPC::Open2 -e \"exit 0\"\n '\n \n-test_expect_success PERL '--batch-command info is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-check $hello_oid \"$expect\"\n+'\n+\n+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n '\n \n test_done\ndiff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh\nindex cc12f99f115..a37509f0043 100755\n--- a/t/t7501-commit-basic-functionality.sh\n+++ b/t/t7501-commit-basic-functionality.sh\n@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '\n \ttest_must_fail git commit -m foo -a file\n '\n \n-test_expect_success PERL 'can use paths with --interactive' '\n+test_expect_success 'can use paths with --interactive' '\n \techo bong-o-bong >file &&\n \t# 2: update, 1:st path, that is all, 7: quit\n \ttest_write_lines 2 1 \"\" 7 |\n@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '\n \tgrep Rubber.Duck output\n '\n \n-test_expect_success PERL 'interactive add' '\n+test_expect_success 'interactive add' '\n \techo 7 | test_must_fail git commit --interactive >out &&\n \tgrep \"What now\" out\n '\n \n-test_expect_success PERL \"commit --interactive doesn't change index if editor aborts\" '\n+test_expect_success \"commit --interactive doesn't change index if editor aborts\" '\n \techo zoo >file &&\n \ttest_must_fail git diff --exit-code >diff1 &&\n \ttest_write_lines u \"*\" q |\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515157","messageId":"20250327-b4-pks-t-perlless-v3-6-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:04Z","receivedAt":"2025-03-27T10:37:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"In the early days of Git, Perl was used quite prominently throughout the\nproject. This has changed significantly as almost all of the executables\nwe ship nowadays have eventually been rewritten in C. Only a handful of\nsubsystems remain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these subsystems can really be considered to be part of the\n\"core\" of Git, and an installation without them is fully functional.\nIt is more likely than not that an end user wouldn't even notice that\nany features are missing if those tools weren't installed. But while\nPerl nowadays very much is an optional dependency of Git, there is a\nsignificant limitation when Perl isn't available: developers cannot run\nour test suite.\n\nPreceding commits have started to lift this restriction by removing the\nstrict dependency on Perl in many central parts of the test library. But\nthere are still many tests that rely on small Perl helpers to do various\ndifferent things.\n\nIntroduce a new PERL_TEST_HELPERS prerequisite that guards all tests\nthat require Perl. This prerequisite is explicitly different than the\npreexisting PERL prerequisite:\n\n  - PERL records whether or not features depending on the Perl\n    interpreter are built.\n\n  - PERL_TEST_HELPERS records whether or not a Perl interpreter is\n    available for our tests.\n\nBy having these two separate prerequisites we can thus distinguish\nbetween tests that inherently depend on Perl because the underlying\nfeature does, and those tests that depend on Perl because the test\nitself is using Perl.\n\nAdapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        |  6 ++++++\n t/t0021-conversion.sh                     |  4 ++--\n t/t0210-trace2-normal.sh                  |  6 ++++++\n t/t0211-trace2-perf.sh                    |  6 ++++++\n t/t0610-reftable-basics.sh                |  2 +-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       |  2 +-\n t/t1007-hash-object.sh                    |  6 +++---\n t/t1010-mktree.sh                         |  4 ++--\n t/t1450-fsck.sh                           |  6 +++---\n t/t3300-funny-names.sh                    |  6 +++---\n t/t4013-diff-various.sh                   |  6 ++++++\n t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------\n t/t4020-diff-external.sh                  |  4 ++--\n t/t4029-diff-trailing-space.sh            |  2 +-\n t/t4030-diff-textconv.sh                  |  6 ++++++\n t/t4031-diff-rewrite-binary.sh            |  2 +-\n t/t4058-diff-duplicates.sh                |  6 ++++++\n t/t4103-apply-binary.sh                   |  6 ++++++\n t/t4116-apply-reverse.sh                  |  6 ++++++\n t/t4150-am.sh                             |  2 +-\n t/t4200-rerere.sh                         |  6 ++++++\n t/t4205-log-pretty-formats.sh             |  6 +++---\n t/t4216-log-bloom.sh                      |  8 ++++----\n t/t5004-archive-corner-cases.sh           |  6 ++++++\n t/t5300-pack-object.sh                    |  6 ++++++\n t/t5303-pack-corruption-resilience.sh     |  4 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               |  8 ++++----\n t/t5318-commit-graph.sh                   | 12 ++++++------\n t/t5319-multi-pack-index.sh               | 16 ++++++++--------\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  2 +-\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  4 ++--\n t/t5503-tagfollow.sh                      |  6 ++++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++++\n t/t5532-fetch-proxy.sh                    |  6 ++++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  |  2 +-\n t/t5551-http-fetch-smart.sh               |  7 +++++++\n t/t5562-http-backend-content-length.sh    |  6 ++++++\n t/t5601-clone.sh                          |  4 ++--\n t/t5616-partial-clone.sh                  |  6 +++---\n t/t5701-git-serve.sh                      |  2 +-\n t/t5702-protocol-v2.sh                    |  6 +++---\n t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++\n t/t5710-promisor-remote-capability.sh     |  6 ++++++\n t/t6002-rev-list-bisect.sh                |  6 ++++++\n t/t6003-rev-list-topo-order.sh            |  6 ++++++\n t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++\n t/t6013-rev-list-reverse-parents.sh       |  4 ++--\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++\n t/t6115-rev-list-du.sh                    |  6 ++++++\n t/t6300-for-each-ref.sh                   |  6 ++++++\n t/t7006-pager.sh                          |  2 +-\n t/t7416-submodule-dash-url.sh             |  6 ++++++\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  6 ++++++\n t/t8001-annotate.sh                       |  6 ++++++\n t/t8002-blame.sh                          |  6 ++++++\n t/t8006-blame-textconv.sh                 |  6 ++++++\n t/t8011-blame-split-file.sh               |  6 +++---\n t/t8012-blame-colors.sh                   |  6 ++++++\n t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib.sh                             |  1 +\n 71 files changed, 281 insertions(+), 93 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c9376dffb58..1aaa6bf5ae8 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,6 +5,12 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping ignores tests; Perl not available'\n+\ttest_done\n+fi\n+\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 3f6433d3045..9c3738ebb3f 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success 'required process filter should process multiple packets' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '\n \t)\n '\n \n-test_expect_success 'required process filter with clean error should fail' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex 4287ed3fbb3..ba4c0442b85 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\ndiff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh\nindex bac90465406..760cf69087f 100755\n--- a/t/t0211-trace2-perf.sh\n+++ b/t/t0211-trace2-perf.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_PERF_BRIEF\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 4618ffc108e..5e0a1fa176d 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success 'basic: can write large commit message' '\n+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \tperl -e \"\ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex e2708e11d5b..fa1e2f9eef8 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success 'small block size fails with large reflog message' '\n+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 398865d6ebe..a574da3df53 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1270,7 +1270,7 @@ extract_batch_output () {\n     ' \"$@\"\n }\n \n-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '\n+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '\n \tgit cat-file --batch-all-objects --batch >actual.raw &&\n \textract_batch_output $orig <actual.raw >actual &&\n \t{\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex a0481139de5..b3cf53ff8c9 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '\n \tgrep \"too-short tree object\" err\n '\n \n-test_expect_success 'malformed mode in tree' '\n+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"9100644 \\0$bin_oid\" >tree-with-malformed-mode &&\n@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '\n \tgrep \"malformed mode in tree entry\" err\n '\n \n-test_expect_success 'empty filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"100644 \\0$bin_oid\" >tree-with-empty-filename &&\n@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '\n \tgrep \"empty filename in tree entry\" err\n '\n \n-test_expect_success 'duplicate filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \t{\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex c291a2b33d7..4977998e205 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n \tperl -e \"print reverse <>\" <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n \tperl -e \"print reverse <>\" <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\ndiff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh\nindex 8a456b1142d..01050453762 100755\n--- a/t/t1450-fsck.sh\n+++ b/t/t1450-fsck.sh\n@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '\n \ttest_grep ! \"fatal: empty filename in tree entry\" out\n '\n \n-test_expect_success 'tree entry with type mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \ttest_when_finished \"remove_object \\$commit\" &&\n@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '\n \ttest_grep ! \"dangling blob\" out\n '\n \n-test_expect_success 'tree entry with bogus mode' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \tblob=$(echo blob | git hash-object -w --stdin) &&\n@@ -984,7 +984,7 @@ corrupt_index_checksum () {\n \n # Corrupt the checksum on the index and then\n # verify that only fsck notices.\n-test_expect_success 'detect corrupt index file in fsck' '\n+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '\n \tcp .git/index .git/index.backup &&\n \ttest_when_finished \"mv .git/index.backup .git/index\" &&\n \tcorrupt_index_checksum &&\ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex f5bf16abcd8..502b1572059 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'ls-files -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-index -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-tree -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 3855d68dbc0..782d97fb7df 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-diff.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff various tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \tGIT_AUTHOR_DATE=\"2006-06-26 00:00:00 +0000\" &&\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 884f83fb8a4..2782b1fc183 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF\n ---\n EOF\n \n-test_expect_success 'no threading' '\n+test_expect_success PERL_TEST_HELPERS 'no threading' '\n \tgit checkout side &&\n \tcheck_threading expect.no-threading main\n '\n@@ -466,11 +466,11 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread' '\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success '--thread overrides format.thread=deep' '\n+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n@@ -490,7 +490,7 @@ In-Reply-To: <1>\n References: <1>\n EOF\n \n-test_expect_success 'thread in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '\n \tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n \t\t--thread main\n '\n@@ -512,7 +512,7 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '\n \tcheck_threading expect.cover-letter --cover-letter --thread main\n '\n \n@@ -538,12 +538,12 @@ References: <1>\n \t<0>\n EOF\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread main\n '\n \n-test_expect_success 'thread explicit shallow' '\n+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=shallow main\n '\n@@ -562,7 +562,7 @@ References: <0>\n \t<1>\n EOF\n \n-test_expect_success 'thread deep' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep' '\n \tcheck_threading expect.deep --thread=deep main\n '\n \n@@ -584,7 +584,7 @@ References: <1>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '\n \tcheck_threading expect.deep-irt  --thread=deep \\\n \t\t--in-reply-to=\"<test.message>\" main\n '\n@@ -609,7 +609,7 @@ References: <0>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '\n \tcheck_threading expect.deep-cl --cover-letter --thread=deep main\n '\n \n@@ -638,27 +638,27 @@ References: <1>\n \t<3>\n EOF\n \n-test_expect_success 'thread deep cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '\n \tcheck_threading expect.deep-cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=deep main\n '\n \n-test_expect_success 'thread via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread via config' '\n \ttest_config format.thread true &&\n \tcheck_threading expect.thread main\n '\n \n-test_expect_success 'thread deep via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.deep main\n '\n \n-test_expect_success 'thread config + override' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + override' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success 'thread config + --no-thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.no-threading --no-thread main\n '\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex f1efe482a59..189294de7ef 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet\n \n echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n \n-test_expect_success 'force diff with \"diff\"' '\n+test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success 'diff --cached' '\n+test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex 32b6e9a4e76..a92a42990b1 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success \"$test_description\" '\n+test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex daebf9796f5..c7d8eb12453 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex c4394a27b56..cbe50b15772 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success 'rewrite diff respects textconv' '\n+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n \tgrep \"dissimilarity index\" diff &&\n \tgrep \"^-61\" diff &&\ndiff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh\nindex 2fce4a98977..16266dff2af 100755\n--- a/t/t4058-diff-duplicates.sh\n+++ b/t/t4058-diff-duplicates.sh\n@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff duplicates tests; Perl not available'\n+\ttest_done\n+fi\n+\n # make_tree_entry <mode> <mode> <sha1>\n #\n # We have to rely on perl here because not all printfs understand\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex d370ecfe0d9..59d38793ae6 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply-binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 0784ba033a4..6f414ad27f5 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,6 +10,12 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply reverse tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 5e2b6c80eae..4794510d70d 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success 'am works with multi-line in-body headers' '\n+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex b0a3e849841..50fe8b0fd05 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rerere tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex f81e42a84d5..8f2ba98963f 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only \"key: value\" trail\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:unfold) unfolds trailers' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '\n \tgit log --no-walk --pretty=\"%(trailers:unfold)\" >actual &&\n \t{\n \t\tunfold <trailers &&\n@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success ':only and :unfold work together' '\n+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '\n \tgit log --no-walk --pretty=\"%(trailers:only,unfold)\" >actual &&\n \tgit log --no-walk --pretty=\"%(trailers:unfold,only)\" >reverse &&\n \ttest_cmp actual reverse &&\n@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '\n \tgit log --no-walk --pretty=\"format:%(trailers:key=Signed-Off-by,unfold)\" >actual &&\n \tunfold <trailers | grep Signed-off-by >expect &&\n \ttest_cmp expect actual\ndiff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh\nindex 3f163dc3969..8910d53cac1 100755\n--- a/t/t4216-log-bloom.sh\n+++ b/t/t4216-log-bloom.sh\n@@ -738,20 +738,20 @@ check_corrupt_graph () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'Bloom reader notices too-small data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '\n \tcheck_corrupt_graph BDAT clear 00000000 &&\n \techo \"warning: ignoring too-small changed-path chunk\" \\\n \t\t\"(4 < 12) in commit-graph file\" >expect.err &&\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '\n \tcheck_corrupt_graph BIDX 12 FFFFFFFF &&\n \t# use grep to avoid depending on exact chunk size\n \tgrep \"warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph\" err\n '\n \n-test_expect_success 'Bloom reader notices too-small index chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '\n \t# replace the index with a single entry, making most\n \t# lookups out-of-bounds\n \tcheck_corrupt_graph BIDX clear 00000000 &&\n@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-order index offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '\n \t# we do not know any real offsets, but we can pick\n \t# something plausible; we should not get to the point of\n \t# actually reading from the bogus offsets anyway.\ndiff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh\nindex 50344e17ca1..51749951916 100755\n--- a/t/t5004-archive-corner-cases.sh\n+++ b/t/t5004-archive-corner-cases.sh\n@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping archive corner cases tests; Perl not available'\n+\ttest_done\n+fi\n+\n # the 10knuls.tar file is used to test for an empty git generated tar\n # without having to invoke tar because an otherwise valid empty GNU tar\n # will be considered broken by {Open,Net}BSD tar\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 5ac8d39094b..143856c29f1 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,6 +7,12 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pack-object tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n \tperl -e \"print \\\"a\\\" x 4096;\" >a &&\ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex de58ca654a1..ac5e370e1e4 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first object' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n@@ -156,7 +156,7 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first delta' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 621bbbdd26e..81987296235 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex 32cf4227451..cd947b5a5ef 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -87,7 +87,7 @@ max_chain() {\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success 'packing produces a long delta' '\n+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth limits depth' '\n+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth=0 disables deltas' '\n+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'negative depth disables deltas' '\n+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\ndiff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh\nindex f68f64cd85e..0b3404f58fe 100755\n--- a/t/t5318-commit-graph.sh\n+++ b/t/t5318-commit-graph.sh\n@@ -837,7 +837,7 @@ check_corrupt_chunk () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \t# make it big enough that the graph file is plausible,\n \t# otherwise we hit an earlier check\n \tcheck_corrupt_chunk OIDF clear $(printf \"000000%02x\" $(test_seq 250)) &&\n@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices fanout/lookup table mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '\n \tcheck_corrupt_chunk OIDF 1020 \"FFFFFFFF\" &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph OID lookup chunk is the wrong size\n@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# Rather than try to corrupt a specific hash, we will just\n \t# wreck them all. But we cannot just set them all to 0xFFFFFFFF or\n \t# similar, as they are used for hi/lo starts in a binary search (so if\n@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small commit data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '\n \tcheck_corrupt_chunk CDAT clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph commit data chunk is wrong size\n@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds extra edge' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '\n \tcheck_corrupt_chunk EDGE clear &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph extra-edges pointer out of bounds\n@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small generations chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '\n \tcheck_corrupt_chunk GDA2 clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph generations chunk is wrong size\ndiff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh\nindex 0f215ad2e88..bd75dea9501 100755\n--- a/t/t5319-multi-pack-index.sh\n+++ b/t/t5319-multi-pack-index.sh\n@@ -1120,7 +1120,7 @@ corrupt_chunk () {\n \tcorrupt_chunk_file $midx \"$@\"\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \tcorrupt_chunk OIDF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small oid lookup chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '\n \tcorrupt_chunk OIDL clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small pack names chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '\n \t# There is no NUL to terminate the name here, so the\n \t# chunk is too short.\n \tcorrupt_chunk PNAM clear 70656666 &&\n@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader handles unaligned chunks' '\n+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '\n \t# A 9-byte PNAM means all of the subsequent chunks\n \t# will no longer be 4-byte aligned, but it is still\n \t# a valid one-pack chunk on its own (it is \"foo.pack\\0\").\n@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small object offset chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '\n \tcorrupt_chunk OOFF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader bounds-checks large offset table' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '\n \t# re-use the objects64 dir here to cheaply get access to a midx\n \t# with large offsets.\n \tgit init repo &&\n@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '\n \t)\n '\n \n-test_expect_success 'reader notices too-small revindex chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '\n \t# We only get a revindex with bitmaps (and likewise only\n \t# load it when they are asked for).\n \ttest_config repack.writeBitmaps true &&\n@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# This is similar to the out-of-bounds fanout test in t5318. The values\n \t# in adjacent entries should be large but not identical (they\n \t# are used as hi/lo starts for a binary search, which would then abort\ndiff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh\nindex a32be3867df..49a057cc2eb 100755\n--- a/t/t5324-split-commit-graph.sh\n+++ b/t/t5324-split-commit-graph.sh\n@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '\n \t)\n '\n \n-test_expect_success 'reader bounds-checks base-graph chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '\n \tgit clone --no-hardlinks . corrupt-base-chunk &&\n \t(\n \t\tcd corrupt-base-chunk &&\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex d27557b9b04..627f8b4efdc 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh\nindex a766a3e3f84..d8891e6a922 100755\n--- a/t/t5328-commit-graph-64bit-time.sh\n+++ b/t/t5328-commit-graph-64bit-time.sh\n@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '\n \tgit -C repo-uint32-max commit-graph verify\n '\n \n-test_expect_success 'reader notices out-of-bounds generation overflow' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '\n \tgraph=.git/objects/info/commit-graph &&\n \ttest_when_finished \"rm -rf $graph\" &&\n \tgit commit-graph write --reachable &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 3905cb6e4f1..1059ff45fe4 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\ndiff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh\nindex 3f81f16e133..571e8f1bc59 100755\n--- a/t/t5400-send-pack.sh\n+++ b/t/t5400-send-pack.sh\n@@ -268,7 +268,7 @@ extract_ref_advertisement () {\n \t'\n }\n \n-test_expect_success 'receive-pack de-dupes .have lines' '\n+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '\n \tgit init shared &&\n \tgit -C shared commit --allow-empty -m both &&\n \tgit clone -s shared fork &&\ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 0b28e4e452f..6a009fdcd71 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -20,7 +20,7 @@ extract_haves () {\n \tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n }\n \n-test_expect_success 'with core.alternateRefsCommand' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success 'with core.alternateRefsPrefixes' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nindex 845ca43ea0a..febe4410417 100755\n--- a/t/t5503-tagfollow.sh\n+++ b/t/t5503-tagfollow.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping tagfollow tests; Perl not available'\n+\ttest_done\n+fi\n+\n # End state of the repository:\n #\n #         T - tag1          S - tag2\ndiff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh\nindex 58074506c59..438250c75ed 100755\n--- a/t/t5504-fetch-receive-strict.sh\n+++ b/t/t5504-fetch-receive-strict.sh\n@@ -359,7 +359,7 @@ test_expect_success \\\n \tgrep \"Cannot demote unterminatedheader\" act\n '\n \n-test_expect_success 'badFilemode is not a strict error' '\n+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '\n \tgit init --bare badmode.git &&\n \ttree=$(\n \t\tcd badmode.git &&\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 5f350facf5e..432a2264e6f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -8,6 +8,12 @@ test_description='Per branch config variables affects \"git fetch\".\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-bundle.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch tests; Perl not available'\n+\ttest_done\n+fi\n+\n D=$(pwd)\n \n test_expect_success setup '\ndiff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh\nindex 37558226290..95d0f33b295 100755\n--- a/t/t5532-fetch-proxy.sh\n+++ b/t/t5532-fetch-proxy.sh\n@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch proxy tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup remote repo' '\n \tgit init remote &&\n \t(cd remote &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex c91a62b77af..342d0423c92 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 37f7547a4ca..77d20d19110 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\ndiff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh\nindex 761fdfcfe6c..b0d4ea78015 100755\n--- a/t/t5551-http-fetch-smart.sh\n+++ b/t/t5551-http-fetch-smart.sh\n@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n+\n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http fetch smart tests; Perl not available'\n+\ttest_done\n+fi\n+\n test \"$HTTP_PROTO\" = \"HTTP/2\" && enable_http2\n start_httpd\n \ndiff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh\nindex f3b158274c4..b6ee06f5c8f 100755\n--- a/t/t5562-http-backend-content-length.sh\n+++ b/t/t5562-http-backend-content-length.sh\n@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http backend content tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_lazy_prereq GZIP 'gzip --version'\n \n verify_http_result() {\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d0c18660e33..d743d986c40 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '\n \tgit -C replay.git index-pack -v --stdin <tmp.pack\n '\n \n-test_expect_success 'clone on case-insensitive fs' '\n+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '\n \tgit init icasefs &&\n \t(\n \t\tcd icasefs &&\n@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '\n \t)\n '\n \n-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '\n+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '\n \tgrep X icasefs/warning &&\n \tgrep x icasefs/warning &&\n \ttest_grep \"the following paths have collided\" icasefs/warning\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 46504519643..bc7e0fec8dc 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -751,7 +751,7 @@ replace_packfile () {\n \t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n }\n \n-test_expect_success 'upon cloning, check that all refs point to objects' '\n+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '\n+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 678a346ed06..200bf06ecb3 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'ignore very large set of prefixes' '\n+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex d3df81e7852..ad5e772cd72 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success 'when server sends \"ready\", expect DELIM' '\n+test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends \"ready\", expect DELIM' '\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n \tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n \ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex 191097171bc..f59d47aa6c6 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n+\ttest_done\n+fi\n+\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\ndiff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh\nindex d2cc69a17e4..9a420cf5605 100755\n--- a/t/t5710-promisor-remote-capability.sh\n+++ b/t/t5710-promisor-remote-capability.sh\n@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping promisor remote capabilities tests; Perl not available'\n+\ttest_done\n+fi\n+\n GIT_TEST_MULTI_PACK_INDEX=0\n GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0\n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex daa009c9a1b..5e1482aff78 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list bisect tests; Perl not available'\n+\ttest_done\n+fi\n+\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 0d7055d46d4..02dd4127aff 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list topo-order tests; Perl not available'\n+\ttest_done\n+fi\n+\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex bad02cf5b83..6131c361094 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 39793cbbd66..8074185742c 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success '--reverse --parents --full-history combines correctly' '\n+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n \tgit rev-list --parents --full-history main -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success '--boundary does too' '\n+test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n \tgit rev-list --boundary --parents --full-history main ^root -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 22dfd6d978e..eb98b3919c8 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list unexpected objects tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup well-formed objects' '\n \tblob=\"$(printf \"foo\" | git hash-object -w --stdin)\" &&\n \ttree=\"$(printf \"100644 blob $blob\\tfoo\" | git mktree)\" &&\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 3385fe9f130..6a74be576a2 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list disk usage tests; Perl not available'\n+\ttest_done\n+fi\n+\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex a5c77943854..732a4d3171e 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping for-each-ref tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 932c26cb45b..49aae183829 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success 'setup large log output' '\n+test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n \tperl -e \"\n \t\tprint \\\"this is a long commit message\\\" x 50000\n \t\" >commit-msg &&\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 0c605fd271a..14069600a2f 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping submodule dash URL tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex b2070d4e39f..14c41b2cb7c 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success 'status -z implies porcelain' '\n+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n \tgit status --porcelain |\n \tperl -pe \"s/\\012/\\000/g\" >expect &&\n \tgit status -z >output &&\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex 90ebb64f46e..b2730d200c8 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,6 +4,12 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping grep binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\ndiff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh\nindex d7167f55397..609845aeb1e 100755\n--- a/t/t8001-annotate.sh\n+++ b/t/t8001-annotate.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping annotate tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git annotate'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex e98993276a6..b40199df231 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 07a287ffd3e..5cb16872081 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,6 +4,12 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\ndiff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh\nindex c66494f5ba7..388057245c8 100755\n--- a/t/t8011-blame-split-file.sh\n+++ b/t/t8011-blame-split-file.sh\n@@ -81,7 +81,7 @@ do\n \t\tgit blame --root -C --$output combined >output\n \t'\n \n-\ttest_expect_success \"$output output finds correct commits\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output finds correct commits\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t5 base\n \t\t1 modified\n@@ -93,7 +93,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct filenames\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct filenames\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t11 one\n \t\t11 two\n@@ -102,7 +102,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct previous pointer\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct previous pointer\" '\n \t\tgenerate_expect >expect <<-EOF &&\n \t\t5 NONE\n \t\t1 $(git rev-parse modified^) one\ndiff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh\nindex c3a5f6d01ff..3d77352650f 100755\n--- a/t/t8012-blame-colors.sh\n+++ b/t/t8012-blame-colors.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex 067b15bad25..a9d38be997c 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success '(supposedly) non-conflicting change from SVN' '\n+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success 'change file but in unrelated area' \"\n+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n \tperl -i.bak -p -e 's/^4\\$/4444/' file &&\ndiff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh\nindex 40427883ec6..0781a8d6ace 100755\n--- a/t/t9350-fast-export.sh\n+++ b/t/t9350-fast-export.sh\n@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '\n \t(cd result && git show main:foo)\n '\n \n-test_expect_success 'fast-export quotes pathnames' '\n+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '\n \tgit init crazy-paths &&\n \ttest_config -C crazy-paths core.protectNTFS false &&\n \t(cd crazy-paths &&\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex 36566ace21b..f619b60f226 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'shell complains of overlong commands' '\n+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n \tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex a62699d6c79..59162a3c834 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1706,6 +1706,7 @@ test -n \"$USE_LIBPCRE2\" && test_set_prereq LIBPCRE2\n test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n test -n \"$SANITIZE_LEAK\" && test_set_prereq SANITIZE_LEAK\n test -n \"$GIT_VALGRIND_ENABLED\" && test_set_prereq VALGRIND\n+test -n \"$PERL_PATH\" && test_set_prereq PERL_TEST_HELPERS\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515156","messageId":"20250327-b4-pks-t-perlless-v3-9-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 09/20] Makefile: stop requiring Perl when running tests","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:07Z","receivedAt":"2025-03-27T10:37:16Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Makefile for our tests has a couple of targets that depend on Perl.\nAdapt those targets to only run conditionally in case Perl is available\non the system so that it becomes possible to run the test suite without\nPerl.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/Makefile | 16 +++++++++++++---\n 1 file changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/t/Makefile b/t/Makefile\nindex 2994eb5fa9a..791e0a09789 100644\n--- a/t/Makefile\n+++ b/t/Makefile\n@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT\n \n all:: $(DEFAULT_TEST_TARGET)\n \n-test: pre-clean check-chainlint check-meson $(TEST_LINT)\n+test: pre-clean check-meson $(TEST_LINT)\n \t$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup\n \n+ifneq ($(PERL_PATH),)\n+test: check-chainlint\n+prove: check-chainlint\n+endif\n+\n failed:\n \t@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \\\n \t\tgrep -l '^failed [1-9]' *.counts | \\\n \t\tsed -n 's/\\.counts$$/.sh/p') && \\\n \ttest -z \"$$failed\" || $(MAKE) $$failed\n \n-prove: pre-clean check-chainlint $(TEST_LINT)\n+prove: pre-clean $(TEST_LINT)\n \t@echo \"*** prove (shell & unit tests) ***\"\n \t@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)\n \t$(MAKE) clean-except-prove-cache\n@@ -132,8 +137,13 @@ check-meson:\n \t\tfi; \\\n \tdone\n \n-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \\\n+test-lint: test-lint-duplicates test-lint-executable \\\n \ttest-lint-filenames\n+ifneq ($(PERL_PATH),)\n+test-lint: test-lint-shell-syntax\n+else\n+GIT_TEST_CHAIN_LINT = 0\n+endif\n ifneq ($(GIT_TEST_CHAIN_LINT),0)\n test-lint: test-chainlint\n endif\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515159","messageId":"20250327-b4-pks-t-perlless-v3-8-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 08/20] meson: stop requiring Perl when tests are enabled","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:06Z","receivedAt":"2025-03-27T10:37:16Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Perl interpreter used to be a strict dependency for running our test\nsuite. This requirement is explicit in the Meson build system, where we\nrequire Perl to be present unless tests have been disabled.\n\nWith the preceding commits we have loosened this restriction so that it\nis now possible to run tests when Perl is unavailable. Loosen the above\nrequirement accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/meson.build b/meson.build\nindex efe2871c9db..d6e27b236fa 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -772,7 +772,7 @@ endif\n # features. It is optional if you want to neither execute tests nor use any of\n # these optional features.\n perl_required = get_option('perl')\n-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n   perl_required = true\n endif\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515158","messageId":"20250327-b4-pks-t-perlless-v3-10-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 10/20] t: refactor tests depending on Perl transliteration operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:08Z","receivedAt":"2025-03-27T10:37:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform character\ntransliteration via the \"y/\" or \"tr/\" operator. These usecases can be\ntrivially replaced with tr(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-sha1.sh    |  4 ++--\n t/lib-diff.sh            |  4 ++--\n t/t3300-funny-names.sh   | 12 ++++++------\n t/t4020-diff-external.sh |  6 +++---\n t/t4103-apply-binary.sh  | 12 +++---------\n t/t4116-apply-reverse.sh | 10 ++--------\n t/t4200-rerere.sh        |  2 +-\n 7 files changed, 19 insertions(+), 31 deletions(-)\n\ndiff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh\nindex bf387d3db14..f03b784ddc2 100755\n--- a/t/helper/test-sha1.sh\n+++ b/t/helper/test-sha1.sh\n@@ -15,7 +15,7 @@ do\n \t\t\t{\n \t\t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\t\ttr \"\\000\" \"g\"\n \t\t\t} | ./t/helper/test-tool $sha1 $cnt\n \t\t)\n \t\tif test \"$expect\" = \"$actual\"\n@@ -61,7 +61,7 @@ do\n \t\t{\n \t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\ttr \"\\000\" \"g\"\n \t\t} | sha1sum |\n \t\tsed -e 's/ .*//'\n \t)\ndiff --git a/t/lib-diff.sh b/t/lib-diff.sh\nindex c4606bd4b7f..12b3c8fcc6a 100644\n--- a/t/lib-diff.sh\n+++ b/t/lib-diff.sh\n@@ -21,8 +21,8 @@ compare_diff_raw_z () {\n     # Also we do not check SHA1 hash generation in this test, which\n     # is a job for t0000-basic.sh\n \n-    perl -pe 'y/\\000/\\012/' <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n-    perl -pe 'y/\\000/\\012/' <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n+    tr \"\\000\" \"\\012\" <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n+    tr \"\\000\" \"\\012\" <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2\n }\n \ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex 502b1572059..dd0586b0073 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n+test_expect_success 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit ls-files -z >ls-files.z &&\n-\tperl -pe \"y/\\000/\\012/\" <ls-files.z >current &&\n+\ttr \"\\000\" \"\\012\" <ls-files.z >current &&\n \ttest_cmp expected current\n '\n \n@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n+test_expect_success 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-index -z --name-status $t0 >diff-index.z &&\n-\tperl -pe \"y/\\000/\\012/\" <diff-index.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-index.z >current &&\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n+test_expect_success 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-tree -z --name-status $t0 $t1 >diff-tree.z &&\n-\tperl -pe y/\\\\000/\\\\012/ <diff-tree.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-tree.z >current &&\n \ttest_cmp expected current\n '\n \ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex 189294de7ef..c8a23d51483 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet\n check_external_diff   1 empty  empty 1 on  --quiet\n check_external_diff 128 empty  error 2 on  --quiet\n \n-echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n+echo NULZbetweenZwords | tr \"Z\" \"\\000\" > file\n \n-test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n+test_expect_success 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n+test_expect_success 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex 59d38793ae6..8e302a5a57e 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply-binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\n@@ -32,10 +26,10 @@ test_expect_success 'setup' '\n \tgit commit -m \"Initial Version\" 2>/dev/null &&\n \n \tgit checkout -b binary &&\n-\tperl -pe \"y/x/\\000/\" <file1 >file3 &&\n+\ttr \"x\" \"\\000\" <file1 >file3 &&\n \tcat file3 >file4 &&\n \tgit add file2 &&\n-\tperl -pe \"y/\\000/v/\" <file3 >file1 &&\n+\ttr \"y\" \"\\000\" <file3 >file1 &&\n \trm -f file2 &&\n \tgit update-index --add --remove file1 file2 file3 file4 &&\n \tgit commit -m \"Second Version\" &&\n@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '\n \ttest -z \"$(git diff --name-status binary -- file3)\"\n '\n \n-test_expect_success 'reject truncated binary diff' '\n+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '\n \tdo_reset &&\n \n \t# this length is calculated to get us very close to\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 6f414ad27f5..1e7beab0016 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,23 +10,17 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply reverse tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\n-\tperl -pe \"y/ijk/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"ijk\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit add file1 file2 &&\n \tgit commit -m initial &&\n \tgit tag initial &&\n \n \ttest_write_lines a b c g h i J K L m o n p q >file1 &&\n-\tperl -pe \"y/mon/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"mon\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit commit -a -m second &&\n \tgit tag second &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 50fe8b0fd05..7fcca9ddad5 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '\n \n test_expect_success 'rerere clear' '\n \tmv $rr/postimage .git/post-saved &&\n-\techo \"$sha1\ta1\" | perl -pe \"y/\\012/\\000/\" >.git/MERGE_RR &&\n+\techo \"$sha1\ta1\" | tr \"\\012\" \"\\000\" >.git/MERGE_RR &&\n \tgit rerere clear &&\n \t! test -d $rr\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515160","messageId":"20250327-b4-pks-t-perlless-v3-11-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:09Z","receivedAt":"2025-03-27T10:37:18Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform substitution via the\n\"s/\" operator. These usecases can be trivially replaced with sed(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        | 10 ++--------\n t/t4029-diff-trailing-space.sh            |  5 +++--\n t/t4200-rerere.sh                         | 12 +++---------\n t/t5303-pack-corruption-resilience.sh     | 10 ++++++----\n t/t5310-pack-bitmaps.sh                   |  4 ++--\n t/t5534-push-signed.sh                    |  4 ++--\n t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------\n t/t7416-submodule-dash-url.sh             |  9 ++-------\n t/t7508-status.sh                         |  4 ++--\n t/t8006-blame-textconv.sh                 |  8 +-------\n t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------\n 11 files changed, 40 insertions(+), 60 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex 1aaa6bf5ae8..273d71411fe 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,12 +5,6 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping ignores tests; Perl not available'\n-\ttest_done\n-fi\n-\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\n@@ -45,11 +39,11 @@ test_stderr () {\n }\n \n broken_c_unquote () {\n-\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n+\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n }\n \n broken_c_unquote_verbose () {\n-\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n+\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n }\n \n stderr_contains () {\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex a92a42990b1..90cdde88d8b 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n+test_expect_success \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\n@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tgit config --bool diff.suppressBlankEmpty true &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\n-\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n+\tsed \"s/^\\$/ /\" exp >exp.munged &&\n+\tmv exp.munged exp &&\n \tgit config --bool diff.suppressBlankEmpty false &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 7fcca9ddad5..204325f4d53 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rerere tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\n@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n \ttest_might_fail git config --unset rerere.enabled &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep \"^=======\\$\" $rr/preimage &&\n \t! test -f $rr/postimage &&\n@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep ^=======$ $rr/preimage\n '\n@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n \tgit config rerere.enabled true &&\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1\n '\n \ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex ac5e370e1e4..ab99c8b6850 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n+test_expect_success 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n+\tsed \"s/ base /abcdef/\" ${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n@@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n+test_expect_success 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n+\tsed \"s/ delta1 /abcdefgh/\" ${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \tgit cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 81987296235..a62b463eaf0 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -421,7 +421,7 @@ test_bitmap_cases () {\n \n \t\t\t# mark the commits which did not receive bitmaps as preferred,\n \t\t\t# and generate the bitmap again\n-\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n \t\t\t\tgit update-ref --stdin &&\n \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n \ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 342d0423c92..2a782214ee1 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n \t# Tweak the push output to make the push option outside the cert\n \t# different, then replay it on a fresh dst, checking that ff is not\n \t# deleted.\n-\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" push >push.tweak &&\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n \tgit -C dst config receive.advertisepushoptions 1 &&\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex 6131c361094..b6f3344dbfb 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\n@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n    first_commit=$(git rev-parse HEAD~3)\n    '\n \n-test_expect_success 'corrupt second commit object' \\\n-   '\n-   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n-   test_must_fail git fsck --full\n-   '\n+test_expect_success 'corrupt second commit object' '\n+\tfor p in .git/objects/pack/*.pack\n+\tdo\n+\t\tsed \"s/second commit/socond commit/\" \"$p\" >\"$p.munged\" &&\n+\t\tmv \"$p.munged\" \"$p\" ||\n+\t\treturn 1\n+\tdone &&\n+\ttest_must_fail git fsck --full\n+'\n \n test_expect_success 'rev-list should fail' '\n \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 14069600a2f..3d944a00e0d 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping submodule dash URL tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\n@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n '\n \n test_expect_success 'remove ./ protection from .gitmodules url' '\n-\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n+\tsed \"s|\\./||\" .gitmodules >.gitmodules.munged &&\n+\tmv .gitmodules.munged .gitmodules &&\n \tgit commit -am \"drop protection\"\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 14c41b2cb7c..cdc1d6fcc78 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n+test_expect_success 'status -z implies porcelain' '\n \tgit status --porcelain |\n-\tperl -pe \"s/\\012/\\000/g\" >expect &&\n+\ttr \"\\012\" \"\\000\" >expect &&\n \tgit status -z >output &&\n \ttest_cmp expect output\n '\ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 5cb16872081..db1e2afb2ca 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,12 +4,6 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping blame textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\n@@ -17,7 +11,7 @@ find_blame() {\n cat >helper <<'EOF'\n #!/bin/sh\n grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n-\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n+sed 's/^bin: /converted: /' \"$1\"\n EOF\n chmod +x helper\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex a9d38be997c..b57a362bb98 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n+test_expect_success '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n \t(cd tmp &&\n-\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n-\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" file >file.munged &&\n+\t\tmv file.munged file &&\n \t\tpoke file &&\n \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n+test_expect_success 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n-\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n-\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n+\tsed -e 's/^4\\$/4444/' \\\n+\t    -e 's/^7\\$/7777/' \\\n+\t\tfile >file.munged &&\n+\tmv file.munged file &&\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n \tgit commit -m '4 => 4444, 7 => 7777' file &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515161","messageId":"20250327-b4-pks-t-perlless-v3-12-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:10Z","receivedAt":"2025-03-27T10:37:20Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A bunch of tests rely on Perl to print data in various different ways.\nThese usages fall into the following categories:\n\n  - Print data conditionally by matching patterns. These usecases can be\n    converted to use awk(1) rather easily.\n\n  - Print data repeatedly. These usecases can typically be converted to\n    use a combination of `test-tool genzeros` and sed(1).\n\n  - Print data in reverse. These usecases can be converted to use\n    awk(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0610-reftable-basics.sh          |  7 +++----\n t/t0613-reftable-write-options.sh   |  4 ++--\n t/t1010-mktree.sh                   |  8 ++++----\n t/t4150-am.sh                       | 10 +++++-----\n t/t5300-pack-object.sh              | 16 +++++-----------\n t/t5326-multi-pack-bitmaps.sh       |  6 +++---\n t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------\n t/t5410-receive-pack-alternates.sh  |  6 +++---\n t/t5701-git-serve.sh                |  7 +++++--\n t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------\n t/t6115-rev-list-du.sh              |  8 +-------\n t/t7006-pager.sh                    |  8 ++++----\n t/t8002-blame.sh                    |  2 +-\n t/t9850-shell.sh                    |  4 ++--\n 14 files changed, 51 insertions(+), 67 deletions(-)\n\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 5e0a1fa176d..77ed11e7172 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n+test_expect_success 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+\n+\tawk \"BEGIN { for (i = 0; i < 50000; i++) printf \\\"%s\\\", \\\"this is a long commit message\\\" }\" >commit-msg &&\n \tgit -C repo commit --allow-empty --file=../commit-msg\n '\n \ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex fa1e2f9eef8..42aa1592f87 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n+test_expect_success 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\n \t\tcd repo &&\n \t\ttest_commit A &&\n-\t\tperl -e \"print \\\"a\\\" x 500\" >logmsg &&\n+\t\ttest-tool genzeros 500 | tr \"\\000\" \"a\" >logmsg &&\n \t\tcat >expect <<-EOF &&\n \t\tfatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large\n \t\tEOF\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex 4977998e205..e9973f74949 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n-\tperl -e \"print reverse <>\" <top |\n+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+\tsort -r <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n-\tperl -e \"print reverse <>\" <top.withsub |\n+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+\tsort -r <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\n '\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 4794510d70d..2ae93d3c967 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n+test_expect_success 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\n@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'\n     Body test\" --author=\"$LONG <long@example.com>\" &&\n \tgit format-patch --stdout -1 >patch &&\n \t# bump from, date, and subject down to in-body header\n-\tperl -lpe \"\n-\t\tif (/^From:/) {\n+\tawk \"\n+\t\t/^From:/{\n \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n \t\t\tprint \\\"Subject: x\\n\\\";\n-\t\t}\n-\t\" patch >msg &&\n+\t\t}; 1\n+\t\" <patch >msg &&\n \tgit checkout HEAD^ &&\n \tgit am msg &&\n \t# Ensure that the author and full message are present\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 143856c29f1..a5932b6a8be 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,17 +7,11 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pack-object tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n-\tperl -e \"print \\\"a\\\" x 4096;\" >a &&\n-\tperl -e \"print \\\"b\\\" x 4096;\" >b &&\n-\tperl -e \"print \\\"c\\\" x 4096;\" >c &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"a\" >a &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"b\" >b &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"c\" >c &&\n \ttest-tool genrandom \"seed a\" 2097152 >a_big &&\n \ttest-tool genrandom \"seed b\" 2097152 >b_big &&\n \tgit update-index --add a a_big b b_big c &&\n@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'\n # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>\n # e.g.: check_deltas stderr -gt 0\n check_deltas() {\n-\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' \"$1\") &&\n \tshift &&\n \tif ! test \"$deltas\" \"$@\"\n \tthen\n@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '\n \tcheck_unpack test-3-${packname_3} obj-list \"$BATCH_CONFIGURATION\"\n '\n \n-test_expect_success 'compare delta flavors' '\n+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '\n \tperl -e '\\''\n \t\tdefined($_ = -s $_) or die for @ARGV;\n \t\texit 1 if $ARGV[0] <= $ARGV[1];\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex 627f8b4efdc..892aeb09e4b 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {\n \t\t\tcomm -13 bitmaps commits >before &&\n \t\t\ttest_line_count = 1 before &&\n \n-\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n-\t\t\t\t<before | git update-ref --stdin &&\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n+\t\t\tgit update-ref --stdin &&\n \n \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n \t\t\trm -fr $midx &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 1059ff45fe4..56674db562f 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\n@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {\n \n tag_everything () {\n \tgit rev-list --all --no-object-names >in &&\n-\tperl -lne '\n-\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n-\t' <in | git update-ref --stdin\n+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' in |\n+\tgit update-ref --stdin\n }\n \n test_expect_success 'setup' '\n@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n \ttest_config bitmapPseudoMerge.test.pattern \"refs/tags/\" &&\n \ttest_config bitmapPseudoMerge.test.maxMerges 1 &&\n \ttest_config bitmapPseudoMerge.test.stableThreshold never &&\n@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\t\ttest_commit_bulk 16 &&\n \n \t\t\tgit rev-list HEAD~16.. >in &&\n-\n-\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n \t\t\tgit update-ref --stdin || return 1\n \t\tdone &&\n \n@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\tdo\n \t\t\ttest_pseudo_merge_commits $m >oids &&\n \t\t\tgrep -f oids refs |\n-\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n+\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n \t\t\tsort -u || return 1\n \t\tdone >remotes &&\n \ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 6a009fdcd71..4e82fd102e3 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -17,10 +17,10 @@ test_expect_success 'setup' '\n '\n \n extract_haves () {\n-\tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n+\tdepacketize | sed -n 's/^\\([^ ][^ ]*\\) \\.have/\\1/p'\n }\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n+test_expect_success 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n+test_expect_success 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 200bf06ecb3..d4c28bae39e 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n+test_expect_success 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\n@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t\techo command=ls-refs &&\n \t\techo object-format=$(test_oid algo) &&\n \t\techo 0001 &&\n-\t\tperl -le \"print \\\"ref-prefix refs/heads/\\$_\\\" for (1..65536)\" &&\n+\t\tawk \"{\n+\t\t\tfor (i = 1; i <= 65536; i++)\n+\t\t\t\tprint \\\"ref-prefix refs/heads/\\\", \\$i\n+\t\t}\" &&\n \t\techo 0000\n \t} |\n \ttest-tool pkt-line pack >in &&\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 8074185742c..273196f52b5 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n-\tgit rev-list --parents --full-history main -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+reverse () {\n+\tawk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'\n+}\n+\n+test_expect_success '--reverse --parents --full-history combines correctly' '\n+\tgit rev-list --parents --full-history main -- foo | reverse >expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n \t\t> actual &&\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n-\tgit rev-list --boundary --parents --full-history main ^root -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+test_expect_success '--boundary does too' '\n+\tgit rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\n \t\tmain ^root -- foo > actual &&\n \ttest_cmp expected actual\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 6a74be576a2..04c577dad69 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list disk usage tests; Perl not available'\n-\ttest_done\n-fi\n-\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\n@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '\n disk_usage_slow () {\n \tgit rev-list --no-object-names \"$@\" |\n \tgit cat-file --batch-check=\"%(objectsize:disk)\" |\n-\tperl -lne '$total += $_; END { print $total}'\n+\tawk '{ i += $1 } END { print i }'\n }\n \n # check behavior with given rev-list options; note that\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 49aae183829..9717e825f0d 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+test_expect_success 'setup large log output' '\n+\ttest-tool genzeros 50000 |\n+\ttr \"\\000\" \"a\" |\n+\tsed \"s/a/this is a long commit message/g\" >commit-msg &&\n \tgit commit --allow-empty -F commit-msg\n '\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex b40199df231..7822947f028 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '\n \t\texpect=$1 && shift &&\n \t\techo $sha1 | cut -c 1-$expect >expect &&\n \t\tgit blame \"$@\" abbrev.t >actual &&\n-\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" actual >actual.sha &&\n \t\ttest_cmp expect actual.sha\n \t}\n '\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex f619b60f226..21c3af48bd0 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n-\tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n+test_expect_success 'shell complains of overlong commands' '\n+\ttest-tool genzeros | tr \"\\000\" \"a\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515162","messageId":"20250327-b4-pks-t-perlless-v3-13-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:11Z","receivedAt":"2025-03-27T10:37:21Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of tests that depend on Perl for textconv scripts.\nRefactor these tests to instead be implemented via shell utilities so\nthat we can drop a couple of PERL_TEST_HELPERS prerequisites.\n\nNote that not all of the conversions are a one-to-one equivalent to the\nprevious textconv scripts. But that's not really needed in the first\nplace: we only care that the textconv script does something, and that\ncan be verified trivially without having a full-blown invocation of\nhexdump. So at times, the implementation of the textconv scripts is\nreduced to their bare minimum and the expectations of those tests are\nadapted accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t4030-diff-textconv.sh       | 15 +++------------\n t/t4031-diff-rewrite-binary.sh | 19 +++++++------------\n t/t7815-grep-binary.sh         | 15 +++------------\n 3 files changed, 13 insertions(+), 36 deletions(-)\n\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex c7d8eb12453..f904fc19f69 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping diff textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\n@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n +1\n EOF\n \n-cat >hexdump <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-chmod +x hexdump\n-\n test_expect_success 'setup binary file with history' '\n+\twrite_script hexdump <<-\\EOF &&\n+\ttr \"\\000\\001\" \"01\" <\"$1\"\n+\tEOF\n \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n '\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex cbe50b15772..15e012ccc7c 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n \tgrep \" rewrite file\" diff\n '\n \n-{\n-\techo \"#!$SHELL_PATH\"\n-\tcat <<'EOF'\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-} >dump\n-chmod +x dump\n-\n test_expect_success 'setup textconv' '\n+\twrite_script dump <<-\\EOF &&\n+\ttest-tool hexdump <\"$1\"\n+\tEOF\n \techo file diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n+test_expect_success 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n-\tgrep \"dissimilarity index\" diff &&\n-\tgrep \"^-61\" diff &&\n-\tgrep \"^-0\" diff\n+\ttest_grep \"dissimilarity index\" diff &&\n+\ttest_grep \"^-3d 0a 00\" diff &&\n+\ttest_grep \"^+3d 0a 01\" diff\n '\n \n test_done\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex b2730d200c8..3bd91da9707 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,12 +4,6 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping grep binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\n@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n \ttest_cmp expect actual\n '\n \n-cat >nul_to_q_textconv <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n-EOF\n-chmod +x nul_to_q_textconv\n-\n test_expect_success 'setup textconv filters' '\n+\twrite_script nul_to_q_textconv <<-\\EOF &&\n+\ttr \"\\000\" \"Q\" <\"$1\"\n+\tEOF\n \techo a diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n '\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515163","messageId":"20250327-b4-pks-t-perlless-v3-14-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:12Z","receivedAt":"2025-03-27T10:37:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\nstdin. Refactor it to instead use awk(1) so that we drop the\nPERL_TEST_HELPERS prerequisite in users of this library.\n\nNote that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\nnow that the test suite doesn't bail out early anymore in case the\nprerequisite isn't set.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-gpg.sh            |  6 +-----\n t/t6300-for-each-ref.sh | 21 ++++++++++-----------\n 2 files changed, 11 insertions(+), 16 deletions(-)\n\ndiff --git a/t/lib-gpg.sh b/t/lib-gpg.sh\nindex 3845b6ac449..937b876bd05 100644\n--- a/t/lib-gpg.sh\n+++ b/t/lib-gpg.sh\n@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '\n '\n \n sanitize_pgp() {\n-\tperl -ne '\n-\t\t/^-----END PGP/ and $in_pgp = 0;\n-\t\tprint unless $in_pgp;\n-\t\t/^-----BEGIN PGP/ and $in_pgp = 1;\n-\t'\n+\tsed \"/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}\"\n }\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 732a4d3171e..5db7038c417 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping for-each-ref tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\n@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '\n \ttest_must_fail git for-each-ref --format=\"%(raw)\" --tcl\n '\n \n-test_expect_success '%(raw) with --perl' '\n+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '\n \tgit for-each-ref --format=\"\\$name= %(raw);\n print \\\"\\$name\\\"\" refs/myblobs/blob1 --perl | perl >actual &&\n \tcmp blob1 actual &&\n@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '\n '\n \n test_trailer_option () {\n+\tif test \"$#\" -eq 3\n+\tthen\n+\t\tprereq=\"$1\"\n+\t\tshift\n+\tfi &&\n \ttitle=$1 option=$2\n \tcat >expect\n-\ttest_expect_success \"$title\" '\n+\ttest_expect_success $prereq \"$title\" '\n \t\tgit for-each-ref --format=\"%($option)\" refs/heads/main >actual &&\n \t\ttest_cmp expect actual &&\n \t\tgit for-each-ref --format=\"%(contents:$option)\" refs/heads/main >actual &&\n@@ -1452,7 +1451,7 @@ test_trailer_option () {\n \t'\n }\n \n-test_trailer_option '%(trailers:unfold) unfolds trailers' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \\\n \t'trailers:unfold' <<-EOF\n \t$(unfold <trailers)\n \n@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \\\n \n \tEOF\n \n-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \\\n \t'trailers:only,unfold' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n \tEOF\n \n-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \\\n \t'trailers:unfold,only' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515164","messageId":"20250327-b4-pks-t-perlless-v3-15-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:13Z","receivedAt":"2025-03-27T10:37:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `name_from_description()` test helper uses Perl to munge a given\ndescription and convert it into a name. Refactor it to instead use a\ncombination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\nprerequisites in users of this library.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-t6000.sh                 | 13 ++++++-------\n t/t6002-rev-list-bisect.sh     |  6 ------\n t/t6003-rev-list-topo-order.sh |  6 ------\n 3 files changed, 6 insertions(+), 19 deletions(-)\n\ndiff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\nindex fba6778ca35..35c54724650 100644\n--- a/t/lib-t6000.sh\n+++ b/t/lib-t6000.sh\n@@ -109,13 +109,12 @@ check_output () {\n # All alphanums translated into -'s which are then compressed and stripped\n # from front and back.\n name_from_description () {\n-\tperl -pe '\n-\t\ts/[^A-Za-z0-9.]/-/g;\n-\t\ts/-+/-/g;\n-\t\ts/-$//;\n-\t\ts/^-//;\n-\t\ty/A-Z/a-z/;\n-\t'\n+\tsed \\\n+\t\t-e 's/[^A-Za-z0-9.]/-/g' \\\n+\t\t-e 's/--*/-/g' \\\n+\t\t-e 's/-$//' \\\n+\t\t-e 's/^-//' \\\n+\t\t-e 'y/A-Z/a-z/'\n }\n \n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex 5e1482aff78..daa009c9a1b 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list bisect tests; Perl not available'\n-\ttest_done\n-fi\n-\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 02dd4127aff..0d7055d46d4 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list topo-order tests; Perl not available'\n-\ttest_done\n-fi\n-\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515165","messageId":"20250327-b4-pks-t-perlless-v3-16-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 16/20] t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:14Z","receivedAt":"2025-03-27T10:37:25Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our Apache HTTPD setup exposes an \"one_time_perl\" endpoint to access\nrepositories. If used, we execute the \"apply-one-time-perl.sh\" CGI\nscript that checks whether we have a \"one-time-perl\" script. If so, that\nscript gets executed so that it can munge what would be served. Once\ndone, the script gets removed so that it doesn't execute a second time.\n\nAs the name says, this functionality expects the user to pass a Perl\nscript. This isn't really necessary though: we can just as easily\nimplement the same thing with arbitrary scripts.\n\nRefactor the code so that we instead expect an arbitrary script to\nexist and rename the functionality to \"one-time-script\". Adapt callers\nto use shell utilities instead of Perl so that we can drop the\nPERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-httpd.sh                       |  2 +-\n t/lib-httpd/apache.conf              |  6 ++---\n t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------\n t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++\n t/t5537-fetch-shallow.sh             | 17 ++++++-------\n t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------\n t/t5702-protocol-v2.sh               | 27 +++++++++++---------\n t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---\n 8 files changed, 86 insertions(+), 77 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex d83bafeab32..5091db949b7 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -165,7 +165,7 @@ prepare_httpd() {\n \tinstall_script broken-smart-http.sh\n \tinstall_script error-smart-http.sh\n \tinstall_script error.sh\n-\tinstall_script apply-one-time-perl.sh\n+\tinstall_script apply-one-time-script.sh\n \tinstall_script nph-custom-auth.sh\n \n \tln -s \"$LIB_HTTPD_MODULE_PATH\" \"$HTTPD_ROOT_PATH/modules\"\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex 022276a6b9a..e631ab0eb5e 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n-<LocationMatch /one_time_perl/>\n+<LocationMatch /one_time_script/>\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n ScriptAlias /error_smart/ error-smart-http.sh/\n ScriptAlias /error/ error.sh/\n-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1\n+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1\n ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Directory ${GIT_EXEC_PATH}>\n \tOptions FollowSymlinks\n@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Files error.sh>\n   Options ExecCGI\n </Files>\n-<Files apply-one-time-perl.sh>\n+<Files apply-one-time-script.sh>\n \tOptions ExecCGI\n </Files>\n <Files ${GIT_EXEC_PATH}/git-http-backend>\ndiff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh\ndeleted file mode 100644\nindex d7f9fed6aee..00000000000\n--- a/t/lib-httpd/apply-one-time-perl.sh\n+++ /dev/null\n@@ -1,27 +0,0 @@\n-#!/bin/sh\n-\n-# If \"one-time-perl\" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,\n-# using the contents of \"one-time-perl\" as the perl command to be run. If the\n-# response was modified as a result, delete \"one-time-perl\" so that subsequent\n-# HTTP responses are no longer modified.\n-#\n-# This can be used to simulate the effects of the repository changing in\n-# between HTTP request-response pairs.\n-if test -f one-time-perl\n-then\n-\tLC_ALL=C\n-\texport LC_ALL\n-\n-\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n-\t\"$PERL_PATH\" -pe \"$(cat one-time-perl)\" out >out_modified\n-\n-\tif cmp -s out out_modified\n-\tthen\n-\t\tcat out\n-\telse\n-\t\tcat out_modified\n-\t\trm one-time-perl\n-\tfi\n-else\n-\t\"$GIT_EXEC_PATH/git-http-backend\"\n-fi\ndiff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh\nnew file mode 100644\nindex 00000000000..b1682944e28\n--- /dev/null\n+++ b/t/lib-httpd/apply-one-time-script.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+# If \"one-time-script\" exists in $HTTPD_ROOT_PATH, run the script on the HTTP\n+# response. If the response was modified as a result, delete \"one-time-script\"\n+# so that subsequent HTTP responses are no longer modified.\n+#\n+# This can be used to simulate the effects of the repository changing in\n+# between HTTP request-response pairs.\n+if test -f one-time-script\n+then\n+\tLC_ALL=C\n+\texport LC_ALL\n+\n+\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n+\t./one-time-script out >out_modified\n+\n+\tif cmp -s out out_modified\n+\tthen\n+\t\tcat out\n+\telse\n+\t\tcat out_modified\n+\t\trm one-time-script\n+\tfi\n+else\n+\t\"$GIT_EXEC_PATH/git-http-backend\"\n+fi\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 77d20d19110..6588ce62264 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\n@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before\n \tgit -C \"$REPO\" config protocol.version 2 &&\n \tgit -C client config protocol.version 2 &&\n \n-\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_perl/repo\" main:a_branch &&\n+\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_script/repo\" main:a_branch &&\n \n \t# Craft a situation in which the server sends back an unshallow request\n \t# with an empty packfile. This is done by refetching with a shorter\n \t# depth (to ensure that the packfile is empty), and overwriting the\n \t# shallow line in the response with the unshallow line we want.\n-\tprintf \"$(test_oid perl)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n-\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" \"\\$1\"\n+\tEOF\n \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n-\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n+\t\tfetch --depth=1 \"$HTTPD_URL/one_time_script/repo\" \\\n \t\tmain:a_branch &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\" &&\n \n \t# Ensure that the resulting repo is consistent, despite our failure to\n \t# fetch.\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex bc7e0fec8dc..1e354e057fa 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -737,21 +737,25 @@ intersperse () {\n \tsed 's/\\(..\\)/'$1'\\1/g'\n }\n \n-# Create a one-time-perl command to replace the existing packfile with $1.\n+# Create a one-time-script command to replace the existing packfile with $1.\n replace_packfile () {\n-\t# The protocol requires that the packfile be sent in sideband 1, hence\n-\t# the extra \\x01 byte at the beginning.\n-\tcp $1 \"$HTTPD_ROOT_PATH/one-time-pack\" &&\n-\techo 'if (/packfile/) {\n-\t\tprint;\n-\t\tmy $length = -s \"one-time-pack\";\n-\t\tprintf \"%04x\\x01\", $length + 5;\n-\t\tprint `cat one-time-pack` . \"0000\";\n-\t\tlast\n-\t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\tcp \"$1\" one-time-pack &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tif grep packfile \"\\$1\" >/dev/null\n+\tthen\n+\t\tsed '/packfile/q' \"\\$1\" &&\n+\t\t# The protocol requires that the packfile be sent in sideband\n+\t\t# 1, hence the extra \\001 byte at the beginning.\n+\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n+\t\tcat \"$PWD/one-time-pack\" &&\n+\t\tprintf \"0000\"\n+\telse\n+\t\tcat \"\\$1\"\n+\tfi\n+\tEOF\n }\n \n-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n+test_expect_success 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t\n \t# section header.\n \ttest_config -C \"$SERVER\" protocol.version 2 &&\n \ttest_must_fail git -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&\n \n \ttest_grep \"did not send all necessary objects\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not\n \n \t# Exercise to make sure it works.\n \tgit -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&\n \t! grep \"missing object referenced by\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \n \t# Clone. The client has deltabase_have but not deltabase_missing.\n \tgit -c protocol.version=2 clone --no-checkout \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo &&\n \tgit -C repo hash-object -w -- \"$SERVER/have.txt\" &&\n \n \t# Sanity check to ensure that the client does not have\n@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \tgrep \"want $(cat deltabase_missing)\" trace &&\n \t! grep \"want $(cat deltabase_have)\" trace &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n # DO NOT add non-httpd-specific tests here, because the last part of this\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex ad5e772cd72..8548854f32e 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n+test_expect_success 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM'\n \n \t# After \"ready\" in the acknowledgments section, pretend that a FLUSH\n \t# (0000) was sent instead of a DELIM (0001).\n-\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/ready/{n;s/0001/0000/;}\" \"$1\"\n+\tEOF\n \n \ttest_must_fail git -C http_child -c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect\n \n \t# After the acknowledgments section, pretend that a DELIM\n \t# (0001) was sent instead of a FLUSH (0000).\n-\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" \"$1\"\n+\tEOF\n \n \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n \t\t-c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \tgrep \"fetch< .*acknowledgments\" log &&\n \t! grep \"fetch< .*ready\" log &&\n \ttest_grep \"expected no other sections to be sent after no .ready.\" err\n@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n-\tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n+\tURI=\"$HTTPD_URL/one_time_script/server\" &&\n \n \tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n \n-\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \"$1\"\n+\tEOF\n \n \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n \t\t--no-tags \\\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex f59d47aa6c6..fc915e7b823 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '\n \t\ttest_commit m3 &&\n \t\tgit tag -d m2 m3\n \t) &&\n-\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo\" &&\n+\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo\" &&\n \tgit -C \"$LOCAL_PRISTINE\" config protocol.version 2\n '\n \n@@ -481,7 +481,9 @@ inconsistency () {\n \t# RPCs during a single negotiation.\n \toid1=$(git -C \"$REPO\" rev-parse $1) &&\n \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n-\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tsed \"s/$oid1/$oid2/\" \"\\$1\"\n+\tEOF\n }\n \n test_expect_success 'server is initially ahead - no ref in want' '\n@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n-\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/main/rain/\" \"$1\"\n+\tEOF\n \ttest_must_fail git -C local fetch 2>err &&\n \n \ttest_grep \"fatal: remote error: unknown ref refs/heads/rain\" err\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515166","messageId":"20250327-b4-pks-t-perlless-v3-17-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:15Z","receivedAt":"2025-03-27T10:37:26Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `generate_random_characters()` helper function generates N\nrandom characters in the range 'a-z' and writes them into a file. The\nlogic currently uses Perl, but it can be adapted rather easily by:\n\n  - Making `test-tool genrandom` generate an infinite stream.\n\n  - Using `tr -dc` to strip all characters which aren't in the range of\n    'a-z'.\n\n  - Using `test_copy_bytes()` to copy the first N bytes.\n\nThis allows us to drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 4a892a91780..bf10d253ec4 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -20,8 +20,7 @@ EOF\n generate_random_characters () {\n \tLEN=$1\n \tNAME=$2\n-\ttest-tool genrandom some-seed $LEN |\n-\t\tperl -pe \"s/./chr((ord($&) % 26) + ord('a'))/sge\" >\"$TEST_ROOT/$NAME\"\n+\ttest-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes \"$LEN\" >\"$TEST_ROOT/$NAME\"\n }\n \n filter_git () {\n@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n+test_expect_success 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n+test_expect_success 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515167","messageId":"20250327-b4-pks-t-perlless-v3-18-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 18/20] t0210: refactor trace2 scrubbing to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:16Z","receivedAt":"2025-03-27T10:37:27Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The output generated by our trace2 mechanism contains several fields\nthat are dependent on the environment they're being run in, which makes\nit somewhat harder to test it. As a countermeasure we scrub the output\nand strip out any fields that contain such information.\n\nThe logic to do so is implemented in Perl, but it can be trivially\nported to instead use sed(1). Refactor the code accordingly so that we\ncan drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------\n t/t0210/scrub_normal.perl | 54 -----------------------------------------\n 2 files changed, 43 insertions(+), 72 deletions(-)\n\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex ba4c0442b85..96c68f65df2 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping trace2 tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\n@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF\n #\n # Implicit return from cmd_<verb> function propagates <code>.\n \n+scrub_normal () {\n+\t# Scrub the variable fields from the normal trace2 output to make\n+\t# testing easier:\n+\t#\n+\t#   1. Various messages include an elapsed time in the middle of the\n+\t#      message. Replace the time with a placeholder to simplify our\n+\t#      HEREDOC in the test script.\n+\t#\n+\t#   2. We expect:\n+\t#\n+\t#        start <argv0> [<argv1> [<argv2> [...]]]\n+\t#\n+\t#      where argv0 might be a relative or absolute path, with or\n+\t#      without quotes, and platform dependent. Replace argv0 with a\n+\t#      token for HEREDOC matching in the test script.\n+\t#\n+\t#   3. Likewise, the 'cmd_path' message breaks out argv[0].\n+\t#\n+\t#      This line is only emitted when RUNTIME_PREFIX is defined,\n+\t#      so just omit it for testing purposes.\n+\t#\n+\t#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's\n+\t#      sake, skip it when parsing normal.\n+\tsed \\\n+\t\t-e 's/elapsed:[0-9]*\\.[0-9][0-9]*\\([eE][-+]\\{0,1\\}[0-9][0-9]*\\)\\{0,1\\}/elapsed:_TIME_/g' \\\n+\t\t-e \"s/^start '[^']*' \\(.*\\)/start _EXE_ \\1/\" \\\n+\t\t-e 's/^start [^ ][^ ]* \\(.*\\)/start _EXE_ \\1/' \\\n+\t\t-e '/^cmd_path/d' \\\n+\t\t-e '/^cmd_ancestry/d'\n+}\n+\n test_expect_success 'normal stream, return code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '\n test_expect_success 'normal stream, return code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 1\n@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '\n \ttest_when_finished \"rm -r traces actual expect\" &&\n \tmkdir traces &&\n \tGIT_TRACE2=\"$(pwd)/traces\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <\"$(ls traces/*)\" >actual &&\n+\tscrub_normal <\"$(ls traces/*)\" >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '\n test_expect_success 'normal stream, exit code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 0\n@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '\n test_expect_success 'normal stream, exit code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 1\n@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '\n test_expect_success 'normal stream, error event' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 003error \"hello world\" \"this is a test\" &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 003error '\\''hello world'\\'' '\\''this is a test'\\''\n@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '\n test_expect_success 'BUG messages are written to trace2' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 007bug &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 007bug\n@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 008bug\n@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 009bug_BUG\n@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 010bug_BUG\n@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '\n \ttest_config_global trace2.normalBrief 1 &&\n \ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '\n \tmv \"$(pwd)/.gitconfig\" \"$(pwd)/real.gitconfig\" &&\n \ttest_config_global include.path \"$(pwd)/real.gitconfig\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\ndiff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl\ndeleted file mode 100644\nindex 7cc4de392a0..00000000000\n--- a/t/t0210/scrub_normal.perl\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-#!/usr/bin/perl\n-#\n-# Scrub the variable fields from the normal trace2 output to\n-# make testing easier.\n-\n-use strict;\n-use warnings;\n-\n-my $float = '[0-9]*\\.[0-9]+([eE][-+]?[0-9]+)?';\n-\n-# This code assumes that the trace2 data was written with bare\n-# turned on (which omits the \"<clock> <file>:<line>\" prefix.\n-\n-while (<>) {\n-    # Various messages include an elapsed time in the middle\n-    # of the message.  Replace the time with a placeholder to\n-    # simplify our HEREDOC in the test script.\n-    s/elapsed:$float/elapsed:_TIME_/g;\n-\n-    my $line = $_;\n-\n-    # we expect:\n-    #    start <argv0> [<argv1> [<argv2> [...]]]\n-    #\n-    # where argv0 might be a relative or absolute path, with\n-    # or without quotes, and platform dependent.  Replace argv0\n-    # with a token for HEREDOC matching in the test script.\n-\n-    if ($line =~ m/^start/) {\n-\t$line =~ /^start\\s+(.*)/;\n-\tmy $argv = $1;\n-\t$argv =~ m/(\\'[^\\']*\\'|[^ ]+)\\s+(.*)/;\n-\tmy $argv_0 = $1;\n-\tmy $argv_rest = $2;\n-\n-\tprint \"start _EXE_ $argv_rest\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_path/) {\n-\t# Likewise, the 'cmd_path' message breaks out argv[0].\n-\t#\n-\t# This line is only emitted when RUNTIME_PREFIX is defined,\n-\t# so just omit it for testing purposes.\n-\t# print \"cmd_path _EXE_\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_ancestry/) {\n-\t# 'cmd_ancestry' is not implemented everywhere, so for portability's\n-\t# sake, skip it when parsing normal.\n-\t#\n-\t# print \"$line\";\n-    }\n-    else {\n-\tprint \"$line\";\n-    }\n-}\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515168","messageId":"20250327-b4-pks-t-perlless-v3-19-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 19/20] t5316: refactor `max_chain()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:17Z","receivedAt":"2025-03-27T10:37:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `max_chain()` helper function is used to extract the maximum delta\nchain of a packfile as printed by git-index-pack(1). The script uses\nPerl to extract that data, but it can be trivially refactored to use\nawk(1) instead.\n\nRefactor the helper accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5316-pack-delta-depth.sh | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex cd947b5a5ef..defaa06d650 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '\n \n max_chain() {\n \tgit index-pack --verify-stat-only \"$1\" >output &&\n-\tperl -lne '\n-\t  BEGIN { $len = 0 }\n-\t  /chain length = (\\d+)/ and $len = $1;\n-\t  END { print $len }\n-\t' output\n+\tawk '\n+\t\tBEGIN { len=0 }\n+\t\t/chain length = [0-9]+:/{ len=$4 }\n+\t\tEND { print len }\n+\t' <output | tr -d ':'\n }\n \n # Note that this whole setup is pretty reliant on the current\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n+test_expect_success 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n+test_expect_success '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n+test_expect_success '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n+test_expect_success 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515169","messageId":"20250327-b4-pks-t-perlless-v3-20-b436de9da1b8@pks.im","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"[PATCH v3 20/20] t5703: refactor test to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-03-27T10:37:18Z","receivedAt":"2025-03-27T10:37:30Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We use Perl due to two different reasons in t5703:\n\n  - To filter advertised capabilities.\n\n  - To set up a CGI script with HTTPD.\n\nRefactor the first category to use `test_grep` instead. Refactoring the\nsecond category would be a bit more involved, so instead we add the\nPERL_TEST_HELPERS prerequisite to those individual tests now.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------\n 1 file changed, 8 insertions(+), 17 deletions(-)\n\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex fc915e7b823..249137b4673 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n-\ttest_done\n-fi\n-\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\n@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '\n \n test_expect_success 'config controls ref-in-want advertisement' '\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant false &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant true &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_file_not_empty out.filter\n+\ttest_grep \"ref-in-want\" out\n '\n \n test_expect_success 'invalid want-ref line' '\n@@ -486,7 +477,7 @@ inconsistency () {\n \tEOF\n }\n \n-test_expect_success 'server is initially ahead - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '\n \ttest_grep \"fatal: remote error: upload-pack: not our ref\" err\n '\n \n-test_expect_success 'server is initially ahead - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server loses a ref - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n\n-- \n2.49.0.472.ge94155a9ec.dirty\n\n"},{"id":"515227","messageId":"dfb0a47e-075d-4288-8d18-03a60bb04737@gmail.com","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-03-28T10:29:52Z","receivedAt":"2025-03-28T10:30:00Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Patrick\n\nOn 27/03/2025 10:36, Patrick Steinhardt wrote:\n> \n> Changes in v3:\n>    - Remove more useless indirections for sed(1).\n\nThanks for removing these, the range-diff below looks good\n\nBest Wishes\n\nPhillip\n\n> Range-diff versus v2:\n> \n>   1:  8c98b24fe4c =  1:  f2fe08ef0ff t: skip chain lint when PERL_PATH is unset\n>   2:  f140153954c =  2:  9dd2edd0a1a t: refactor environment sanitization to not use Perl\n>   3:  94b5591f666 =  3:  c77424e6907 t: adapt character translation helpers to not use Perl\n>   4:  a5880fdb8ef =  4:  476d1b15932 t: adapt `test_copy_bytes()` to not use Perl\n>   5:  3b64c99c061 =  5:  14badee2551 t: adapt `test_readlink()` to not use Perl\n>   6:  a3536260e4c =  6:  9a88a46bd10 t: introduce PERL_TEST_HELPERS prerequisite\n>   7:  98961b0e065 =  7:  e7413bf28ae t: adapt existing PERL prerequisites\n>   8:  bbdd1fe6c7c =  8:  581a9bedd22 meson: stop requiring Perl when tests are enabled\n>   9:  bda7e7922ce =  9:  cfe1797ae74 Makefile: stop requiring Perl when running tests\n> 10:  d95d50c4b73 = 10:  99e678b83a6 t: refactor tests depending on Perl transliteration operator\n> 11:  f5b30cc3f8f ! 11:  93a98d3e3cf t: refactor tests depending on Perl substitution operator\n>      @@ t/t4029-diff-trailing-space.sh: test_expect_success PERL_TEST_HELPERS \"$test_des\n>        \tgit diff f > actual &&\n>        \ttest_cmp exp actual &&\n>       -\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n>      -+\tsed \"s/^\\$/ /\" <exp >exp.munged &&\n>      ++\tsed \"s/^\\$/ /\" exp >exp.munged &&\n>       +\tmv exp.munged exp &&\n>        \tgit config --bool diff.suppressBlankEmpty false &&\n>        \tgit diff f > actual &&\n>      @@ t/t4200-rerere.sh: test_expect_success 'activate rerere, old style (conflicting\n>        \ttest_must_fail git merge first &&\n>        \n>       -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n>      -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>      ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n>        \trr=.git/rr-cache/$sha1 &&\n>        \tgrep \"^=======\\$\" $rr/preimage &&\n>        \t! test -f $rr/postimage &&\n>      @@ t/t4200-rerere.sh: test_expect_success 'rerere.enabled works, too' '\n>        \ttest_must_fail git merge first &&\n>        \n>       -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n>      -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>      ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n>        \trr=.git/rr-cache/$sha1 &&\n>        \tgrep ^=======$ $rr/preimage\n>        '\n>      @@ t/t4200-rerere.sh: test_expect_success 'set up rr-cache' '\n>        \tgit reset --hard &&\n>        \ttest_must_fail git merge first &&\n>       -\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n>      -+\tsha1=$(sed \"s/\t.*//\" <.git/MERGE_RR) &&\n>      ++\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n>        \trr=.git/rr-cache/$sha1\n>        '\n>        \n>      @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and loose copy o\n>        \tgit prune-packed &&\n>        \tchmod +w ${pack}.pack &&\n>       -\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n>      -+\tsed \"s/ base /abcdef/\" <${pack}.pack >${pack}.pack.munged &&\n>      ++\tsed \"s/ base /abcdef/\" ${pack}.pack >${pack}.pack.munged &&\n>       +\tmv ${pack}.pack.munged ${pack}.pack &&\n>        \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n>        \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>      @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and then a repac\n>        \tgit prune-packed &&\n>        \tchmod +w ${pack}.pack &&\n>       -\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n>      -+\tsed \"s/ delta1 /abcdefgh/\" <${pack}.pack >${pack}.pack.munged &&\n>      ++\tsed \"s/ delta1 /abcdefgh/\" ${pack}.pack >${pack}.pack.munged &&\n>       +\tmv ${pack}.pack.munged ${pack}.pack &&\n>        \tgit cat-file blob $blob_1 > /dev/null &&\n>        \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n>      @@ t/t5310-pack-bitmaps.sh: test_bitmap_cases () {\n>        \t\t\t# mark the commits which did not receive bitmaps as preferred,\n>        \t\t\t# and generate the bitmap again\n>       -\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n>      -+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n>      ++\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n>        \t\t\t\tgit update-ref --stdin &&\n>        \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n>        \n>      @@ t/t5534-push-signed.sh: test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent\n>        \t# different, then replay it on a fresh dst, checking that ff is not\n>        \t# deleted.\n>       -\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n>      -+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" <push >push.tweak &&\n>      ++\tsed \"s/\\([^ ]\\)bar/\\1baz/\" push >push.tweak &&\n>        \tprepare_dst &&\n>        \tgit -C dst config receive.certnonceseed sekrit &&\n>        \tgit -C dst config receive.advertisepushoptions 1 &&\n>      @@ t/t6011-rev-list-with-bad-commit.sh: test_expect_success 'verify number of revis\n>       +test_expect_success 'corrupt second commit object' '\n>       +\tfor p in .git/objects/pack/*.pack\n>       +\tdo\n>      -+\t\tsed \"s/second commit/socond commit/\" <\"$p\" >\"$p.munged\" &&\n>      ++\t\tsed \"s/second commit/socond commit/\" \"$p\" >\"$p.munged\" &&\n>       +\t\tmv \"$p.munged\" \"$p\" ||\n>       +\t\treturn 1\n>       +\tdone &&\n>      @@ t/t7416-submodule-dash-url.sh: test_expect_success 'fsck accepts protected dash'\n>        \n>        test_expect_success 'remove ./ protection from .gitmodules url' '\n>       -\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n>      -+\tsed \"s|\\./||\" <.gitmodules >.gitmodules.munged &&\n>      ++\tsed \"s|\\./||\" .gitmodules >.gitmodules.munged &&\n>       +\tmv .gitmodules.munged .gitmodules &&\n>        \tgit commit -am \"drop protection\"\n>        '\n>      @@ t/t8006-blame-textconv.sh: find_blame() {\n>        #!/bin/sh\n>        grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n>       -\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n>      -+sed 's/^bin: /converted: /' <\"$1\"\n>      ++sed 's/^bin: /converted: /' \"$1\"\n>        EOF\n>        chmod +x helper\n>        \n>      @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'initialize repo'\n>        \t(cd tmp &&\n>       -\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n>       -\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n>      -+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" <file >file.munged &&\n>      ++\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" file >file.munged &&\n>       +\t\tmv file.munged file &&\n>        \t\tpoke file &&\n>        \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n>      @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'some unrelated c\n>       -\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n>       +\tsed -e 's/^4\\$/4444/' \\\n>       +\t    -e 's/^7\\$/7777/' \\\n>      -+\t\t<file >file.munged &&\n>      ++\t\tfile >file.munged &&\n>       +\tmv file.munged file &&\n>        \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n>        \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n> 12:  e978d8ecfde ! 12:  17f862eaba3 t: refactor tests depending on Perl to print data\n>      @@ t/t5300-pack-object.sh: test_expect_success 'pack-object <stdin parsing: --stdin\n>        # e.g.: check_deltas stderr -gt 0\n>        check_deltas() {\n>       -\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n>      -+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' <\"$1\") &&\n>      ++\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' \"$1\") &&\n>        \tshift &&\n>        \tif ! test \"$deltas\" \"$@\"\n>        \tthen\n>      @@ t/t5326-multi-pack-bitmaps.sh: test_midx_bitmap_cases () {\n>        \n>       -\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n>       -\t\t\t\t<before | git update-ref --stdin &&\n>      -+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" <before |\n>      ++\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n>       +\t\t\tgit update-ref --stdin &&\n>        \n>        \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n>      @@ t/t5333-pseudo-merge-bitmaps.sh: test_pseudo_merges_reused () {\n>       -\tperl -lne '\n>       -\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n>       -\t' <in | git update-ref --stdin\n>      -+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' <in |\n>      ++\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' in |\n>       +\tgit update-ref --stdin\n>        }\n>        \n>      @@ t/t5333-pseudo-merge-bitmaps.sh: test_expect_success 'pseudo-merge pattern with\n>        \t\t\tgit rev-list HEAD~16.. >in &&\n>       -\n>       -\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n>      -+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" <in |\n>      ++\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n>        \t\t\tgit update-ref --stdin || return 1\n>        \t\tdone &&\n>        \n>      @@ t/t8002-blame.sh: test_expect_success 'set up abbrev tests' '\n>        \t\techo $sha1 | cut -c 1-$expect >expect &&\n>        \t\tgit blame \"$@\" abbrev.t >actual &&\n>       -\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n>      -+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" <actual >actual.sha &&\n>      ++\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" actual >actual.sha &&\n>        \t\ttest_cmp expect actual.sha\n>        \t}\n>        '\n> 13:  905c25c9fb2 = 13:  7b03d096ccd t: refactor tests depending on Perl for textconv scripts\n> 14:  1fe67bba30f = 14:  195c0bf2445 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n> 15:  9e572c3ba67 = 15:  e92d178b96b t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n> 16:  24abcffe96e ! 16:  0f2c9ad276b t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n>      @@ t/t5537-fetch-shallow.sh: test_expect_success PERL_TEST_HELPERS 'shallow fetches\n>       -\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n>       -\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n>      -+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" <\"\\$1\"\n>      ++\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" \"\\$1\"\n>       +\tEOF\n>        \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n>       -\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n>      @@ t/t5616-partial-clone.sh: intersperse () {\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n>       +\tif grep packfile \"\\$1\" >/dev/null\n>       +\tthen\n>      -+\t\tsed '/packfile/q' <\"\\$1\" &&\n>      ++\t\tsed '/packfile/q' \"\\$1\" &&\n>       +\t\t# The protocol requires that the packfile be sent in sideband\n>       +\t\t# 1, hence the extra \\001 byte at the beginning.\n>       +\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n>      @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server sends\n>       -\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n>       -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n>      -+\tsed \"/ready/{n;s/0001/0000/;}\" <\"$1\"\n>      ++\tsed \"/ready/{n;s/0001/0000/;}\" \"$1\"\n>       +\tEOF\n>        \n>        \ttest_must_fail git -C http_child -c protocol.version=2 \\\n>      @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server does\n>       -\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n>       -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n>      -+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" <\"$1\"\n>      ++\tsed \"/acknowledgments/,//{s/0000/0001/;}\" \"$1\"\n>       +\tEOF\n>        \n>        \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n>      @@ t/t5702-protocol-v2.sh: test_expect_success 'http:// --negotiate-only' '\n>       -\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n>       -\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n>      -+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" <\"$1\"\n>      ++\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \"$1\"\n>       +\tEOF\n>        \n>        \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n>      @@ t/t5703-upload-pack-ref-in-want.sh: inconsistency () {\n>        \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n>       -\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n>      -+\tsed \"s/$oid1/$oid2/\" <\"\\$1\"\n>      ++\tsed \"s/$oid1/$oid2/\" \"\\$1\"\n>       +\tEOF\n>        }\n>        \n>      @@ t/t5703-upload-pack-ref-in-want.sh: test_expect_success 'server loses a ref - re\n>        \tcp -r \"$LOCAL_PRISTINE\" local &&\n>       -\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n>       +\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n>      -+\tsed \"s/main/rain/\" <\"$1\"\n>      ++\tsed \"s/main/rain/\" \"$1\"\n>       +\tEOF\n>        \ttest_must_fail git -C local fetch 2>err &&\n>        \n> 17:  ce5adbd4818 = 17:  9857b461ed6 t0021: refactor `generate_random_characters()` to not depend on Perl\n> 18:  e183c397da9 = 18:  7924b5bd9bf t0210: refactor trace2 scrubbing to not use Perl\n> 19:  156bdc4d62d = 19:  5d6996a1412 t5316: refactor `max_chain()` to not depend on Perl\n> 20:  3b181d0a203 = 20:  0c3afb70128 t5703: refactor test to not depend on Perl\n> \n> ---\n> base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e\n> change-id: 20250317-b4-pks-t-perlless-138cf94696b8\n> \n> \n"},{"id":"515458","messageId":"ee5e082f-6ab5-b996-9a0d-f7e5192c01be@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-6-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T18:26:36Z","receivedAt":"2025-04-01T18:26:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> In the early days of Git, Perl was used quite prominently throughout the\n> project. This has changed significantly as almost all of the executables\n> we ship nowadays have eventually been rewritten in C. Only a handful of\n> subsystems remain that require Perl:\n>\n>   - gitweb, a read-only web interface.\n>\n>   - A couple of scripts that allow importing repositories from GNU Arch,\n>     CVS and Subversion.\n>\n>   - git-send-email(1), which can be used to send mails.\n\nThere is also `git request-pull` which is a _shell_ script that runs\n`perl` to parse the output of `ls-remote`, and there is `git\nfilter-branch` (which was apparently not yet dropped?) that uses Perl if\nthe `--state-branch` option is in use.\n\n>   - Our Perl bindings for Git.\n>\n>   - The netrc Git credential helper.\n>\n> None of these subsystems can really be considered to be part of the\n> \"core\" of Git, and an installation without them is fully functional.\n> It is more likely than not that an end user wouldn't even notice that\n> any features are missing if those tools weren't installed. But while\n> Perl nowadays very much is an optional dependency of Git, there is a\n> significant limitation when Perl isn't available: developers cannot run\n> our test suite.\n>\n> Preceding commits have started to lift this restriction by removing the\n> strict dependency on Perl in many central parts of the test library. But\n> there are still many tests that rely on small Perl helpers to do various\n> different things.\n>\n> Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests\n> that require Perl. This prerequisite is explicitly different than the\n> preexisting PERL prerequisite:\n>\n>   - PERL records whether or not features depending on the Perl\n>     interpreter are built.\n>\n>   - PERL_TEST_HELPERS records whether or not a Perl interpreter is\n>     available for our tests.\n>\n> By having these two separate prerequisites we can thus distinguish\n> between tests that inherently depend on Perl because the underlying\n> feature does, and those tests that depend on Perl because the test\n> itself is using Perl.\n>\n> Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.\n\nThe patch looks good, in particular when fetching the `b4/pks-t-perlless`\nbranch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f\nmanually, as it is a rather large patch that is pretty much unreviewable\non a mailing list.\n\nUsing several write-only `sed` invocations, I identified that there are\nonly three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`\nprereq nor adding a test preamble of this form:\n\n\tif ! test_have_prereq PERL_TEST_HELPERS\n\tthen\n\t\tskip_all='skipping <something>; Perl not available'\n\t\ttest_done\n\tfi\n\nSkipping to only the affected files, these three instances are:\n\n> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\n> index c91a62b77af..342d0423c92 100755\n> --- a/t/t5534-push-signed.sh\n> +++ b/t/t5534-push-signed.sh\n> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n>  \ttest_cmp expect dst/push-cert-status\n>  '\n>\n> -test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n> +test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n>  \t# First, invoke receive-pack with dummy input to obtain its preamble.\n>  \tprepare_dst &&\n>  \tgit -C dst config receive.certnonceseed sekrit &&\n\nHere, that prereq is appended.\n\n> diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\n> index d0c18660e33..d743d986c40 100755\n> --- a/t/t5601-clone.sh\n> +++ b/t/t5601-clone.sh\n> @@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '\n>  \tgit -C replay.git index-pack -v --stdin <tmp.pack\n>  '\n>\n> -test_expect_success 'clone on case-insensitive fs' '\n> +test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '\n>  \tgit init icasefs &&\n>  \t(\n>  \t\tcd icasefs &&\n> @@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '\n>  \t)\n>  '\n>\n> -test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '\n> +test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '\n>  \tgrep X icasefs/warning &&\n>  \tgrep x icasefs/warning &&\n>  \ttest_grep \"the following paths have collided\" icasefs/warning\n\nHere, too.\n\n> diff --git a/t/test-lib.sh b/t/test-lib.sh\n> index a62699d6c79..59162a3c834 100644\n> --- a/t/test-lib.sh\n> +++ b/t/test-lib.sh\n> @@ -1706,6 +1706,7 @@ test -n \"$USE_LIBPCRE2\" && test_set_prereq LIBPCRE2\n>  test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n>  test -n \"$SANITIZE_LEAK\" && test_set_prereq SANITIZE_LEAK\n>  test -n \"$GIT_VALGRIND_ENABLED\" && test_set_prereq VALGRIND\n> +test -n \"$PERL_PATH\" && test_set_prereq PERL_TEST_HELPERS\n>\n>  if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n>  then\n\nAnd this is obviously correct, too.\n\nThank you,\nJohannes\n\n"},{"id":"515459","messageId":"70026fe9-8c99-ab00-531f-1556db63b0d8@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-11-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T18:32:02Z","receivedAt":"2025-04-01T18:32:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> We have a bunch of tests that use Perl to perform substitution via the\n> \"s/\" operator. These usecases can be trivially replaced with sed(1).\n\n... and sometimes `tr`.\n\nIn fact, it looks like...\n\n> diff --git a/t/t7508-status.sh b/t/t7508-status.sh\n> index 14c41b2cb7c..cdc1d6fcc78 100755\n> --- a/t/t7508-status.sh\n> +++ b/t/t7508-status.sh\n> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n>  \ttest_cmp expect output\n>  '\n>\n> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n> +test_expect_success 'status -z implies porcelain' '\n>  \tgit status --porcelain |\n> -\tperl -pe \"s/\\012/\\000/g\" >expect &&\n> +\ttr \"\\012\" \"\\000\" >expect &&\n>  \tgit status -z >output &&\n>  \ttest_cmp expect output\n>  '\n\n... this change is not about `sed` at all, but only about `tr`.\n_Technically_, this hunk would therefore feel more at home in the previous\npatch. But practically, I actually do not mind it being here at all.\n\nThank you,\nJohannes\n"},{"id":"515460","messageId":"4d461a62-9cf5-c64d-cd97-c70ef53afbac@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-12-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 12/20] t: refactor tests depending on Perl to print data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T18:35:25Z","receivedAt":"2025-04-01T18:35:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> A bunch of tests rely on Perl to print data in various different ways.\n> These usages fall into the following categories:\n>\n>   - Print data conditionally by matching patterns. These usecases can be\n>     converted to use awk(1) rather easily.\n>\n>   - Print data repeatedly. These usecases can typically be converted to\n>     use a combination of `test-tool genzeros` and sed(1).\n\nIt might be even more elegant to teach `genzeros` to generate streams of\nbytes other than NUL.\n\n>   - Print data in reverse. These usecases can be converted to use\n>     awk(1).\n\nOr, in one case, `sort -r`.\n\nThese changes all look good to me.\n\nCiao,\nJohannes\n"},{"id":"515462","messageId":"9f477166-5667-a051-13d3-43d56a7a8ec1@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-13-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T18:55:22Z","receivedAt":"2025-04-01T18:55:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> We have a couple of tests that depend on Perl for textconv scripts.\n> Refactor these tests to instead be implemented via shell utilities so\n> that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n>\n> Note that not all of the conversions are a one-to-one equivalent to the\n> previous textconv scripts. But that's not really needed in the first\n> place: we only care that the textconv script does something, and that\n> can be verified trivially without having a full-blown invocation of\n> hexdump. So at times, the implementation of the textconv scripts is\n> reduced to their bare minimum and the expectations of those tests are\n> adapted accordingly.\n\nHmm. I am having a harder time with this patch than with the others. See\nbelow.\n\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/t4030-diff-textconv.sh       | 15 +++------------\n>  t/t4031-diff-rewrite-binary.sh | 19 +++++++------------\n>  t/t7815-grep-binary.sh         | 15 +++------------\n>  3 files changed, 13 insertions(+), 36 deletions(-)\n>\n> diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\n> index c7d8eb12453..f904fc19f69 100755\n> --- a/t/t4030-diff-textconv.sh\n> +++ b/t/t4030-diff-textconv.sh\n> @@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'\n>\n>  . ./test-lib.sh\n>\n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping diff textconv tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>  find_diff() {\n>  \tsed '1,/^index /d' | sed '/^-- $/,$d'\n>  }\n> @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n>  +1\n>  EOF\n>\n> -cat >hexdump <<'EOF'\n> -#!/bin/sh\n> -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> -EOF\n> -chmod +x hexdump\n> -\n>  test_expect_success 'setup binary file with history' '\n> +\twrite_script hexdump <<-\\EOF &&\n> +\ttr \"\\000\\001\" \"01\" <\"$1\"\n> +\tEOF\n\nSo here the `hexdump` script is written, basically replacing NUL and SOH\nwith the digits zero and one, respectively. I wonder why the script does\nnot call `test-tool hexdump` instead? And I wonder even more why no test\ncase has to be adapted below this change in the same file. I _guess_ that\nthe reason is that the file named, creatively, \"file\" is initialized with\na NUL and a newline, committed, then a line is appended that contains SOH\nand a newline, and then the test cases verify the hunk _headers_ only?\n\nIf using `test-tool hexdump <\"$1\"` would work here, too, I'd actually have\npreferred that over the `tr` invocation, even if would still not be\nrecapitulating the functionality of that Perl script (which, contrary to\nits name, seemed never to have output hexadecimal values...).\n\nTo be clear: I do not suggest to change the patch, I am merely puzzled why\nthe more obvious `test-tool hexdump <\"$1\"` was not used here?\n\n>  \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n>  \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n>  '\n> diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\n> index cbe50b15772..15e012ccc7c 100755\n> --- a/t/t4031-diff-rewrite-binary.sh\n> +++ b/t/t4031-diff-rewrite-binary.sh\n> @@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n>  \tgrep \" rewrite file\" diff\n>  '\n>\n> -{\n> -\techo \"#!$SHELL_PATH\"\n> -\tcat <<'EOF'\n> -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> -EOF\n> -} >dump\n> -chmod +x dump\n> -\n>  test_expect_success 'setup textconv' '\n> +\twrite_script dump <<-\\EOF &&\n> +\ttest-tool hexdump <\"$1\"\n> +\tEOF\n\nSo this looks much more like what I would have expected also in t4030,\nand...\n\n>  \techo file diff=foo >.gitattributes &&\n>  \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n>  '\n>\n> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n> +test_expect_success 'rewrite diff respects textconv' '\n>  \tgit diff -B >diff &&\n> -\tgrep \"dissimilarity index\" diff &&\n> -\tgrep \"^-61\" diff &&\n> -\tgrep \"^-0\" diff\n> +\ttest_grep \"dissimilarity index\" diff &&\n> +\ttest_grep \"^-3d 0a 00\" diff &&\n> +\ttest_grep \"^+3d 0a 01\" diff\n>  '\n\n... the adjustment of the expectations is actually going above and beyond,\nthe original test was not half as stringent as the new test is.\n\nThe rest of the patch looks good to me.\n\nCiao,\nJohannes\n\n>\n>  test_done\n> diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\n> index b2730d200c8..3bd91da9707 100755\n> --- a/t/t7815-grep-binary.sh\n> +++ b/t/t7815-grep-binary.sh\n> @@ -4,12 +4,6 @@ test_description='git grep in binary files'\n>\n>  . ./test-lib.sh\n>\n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping grep binary tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>  test_expect_success 'setup' \"\n>  \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n>  \tgit add a &&\n> @@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n>  \ttest_cmp expect actual\n>  '\n>\n> -cat >nul_to_q_textconv <<'EOF'\n> -#!/bin/sh\n> -\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n> -EOF\n> -chmod +x nul_to_q_textconv\n> -\n>  test_expect_success 'setup textconv filters' '\n> +\twrite_script nul_to_q_textconv <<-\\EOF &&\n> +\ttr \"\\000\" \"Q\" <\"$1\"\n> +\tEOF\n>  \techo a diff=foo >.gitattributes &&\n>  \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n>  '\n>\n> --\n> 2.49.0.472.ge94155a9ec.dirty\n>\n>\n"},{"id":"515463","messageId":"c909b89f-7432-2d35-cfdb-0de9f94a7281@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-14-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T18:56:41Z","receivedAt":"2025-04-01T18:56:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nHi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\n> stdin. Refactor it to instead use awk(1) so that we drop the\n> PERL_TEST_HELPERS prerequisite in users of this library.\n\nIt's my fault that this commit message is no longer correct because I\ntalked you into using `sed` instead...\n\nSorry,\nJohannes\n\n>\n> Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\n> now that the test suite doesn't bail out early anymore in case the\n> prerequisite isn't set.\n>\n> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/lib-gpg.sh            |  6 +-----\n>  t/t6300-for-each-ref.sh | 21 ++++++++++-----------\n>  2 files changed, 11 insertions(+), 16 deletions(-)\n>\n> diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh\n> index 3845b6ac449..937b876bd05 100644\n> --- a/t/lib-gpg.sh\n> +++ b/t/lib-gpg.sh\n> @@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '\n>  '\n>\n>  sanitize_pgp() {\n> -\tperl -ne '\n> -\t\t/^-----END PGP/ and $in_pgp = 0;\n> -\t\tprint unless $in_pgp;\n> -\t\t/^-----BEGIN PGP/ and $in_pgp = 1;\n> -\t'\n> +\tsed \"/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}\"\n>  }\n> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n> index 732a4d3171e..5db7038c417 100755\n> --- a/t/t6300-for-each-ref.sh\n> +++ b/t/t6300-for-each-ref.sh\n> @@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n>  . \"$TEST_DIRECTORY\"/lib-gpg.sh\n>  . \"$TEST_DIRECTORY\"/lib-terminal.sh\n>\n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping for-each-ref tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>  # Mon Jul 3 23:18:43 2006 +0000\n>  datestamp=1151968723\n>  setdate_and_increment () {\n> @@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '\n>  \ttest_must_fail git for-each-ref --format=\"%(raw)\" --tcl\n>  '\n>\n> -test_expect_success '%(raw) with --perl' '\n> +test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '\n>  \tgit for-each-ref --format=\"\\$name= %(raw);\n>  print \\\"\\$name\\\"\" refs/myblobs/blob1 --perl | perl >actual &&\n>  \tcmp blob1 actual &&\n> @@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '\n>  '\n>\n>  test_trailer_option () {\n> +\tif test \"$#\" -eq 3\n> +\tthen\n> +\t\tprereq=\"$1\"\n> +\t\tshift\n> +\tfi &&\n>  \ttitle=$1 option=$2\n>  \tcat >expect\n> -\ttest_expect_success \"$title\" '\n> +\ttest_expect_success $prereq \"$title\" '\n>  \t\tgit for-each-ref --format=\"%($option)\" refs/heads/main >actual &&\n>  \t\ttest_cmp expect actual &&\n>  \t\tgit for-each-ref --format=\"%(contents:$option)\" refs/heads/main >actual &&\n> @@ -1452,7 +1451,7 @@ test_trailer_option () {\n>  \t'\n>  }\n>\n> -test_trailer_option '%(trailers:unfold) unfolds trailers' \\\n> +test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \\\n>  \t'trailers:unfold' <<-EOF\n>  \t$(unfold <trailers)\n>\n> @@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \\\n>\n>  \tEOF\n>\n> -test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \\\n> +test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \\\n>  \t'trailers:only,unfold' <<-EOF\n>  \t$(grep -v patch.description <trailers | unfold)\n>\n>  \tEOF\n>\n> -test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \\\n> +test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \\\n>  \t'trailers:unfold,only' <<-EOF\n>  \t$(grep -v patch.description <trailers | unfold)\n>\n>\n> --\n> 2.49.0.472.ge94155a9ec.dirty\n>\n>\n"},{"id":"515464","messageId":"92fd1e8b-4790-0c81-409a-be81aed9f290@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-17-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-01T19:04:44Z","receivedAt":"2025-04-01T19:04:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> The `generate_random_characters()` helper function generates N\n> random characters in the range 'a-z' and writes them into a file. The\n> logic currently uses Perl, but it can be adapted rather easily by:\n>\n>   - Making `test-tool genrandom` generate an infinite stream.\n>\n>   - Using `tr -dc` to strip all characters which aren't in the range of\n>     'a-z'.\n>\n>   - Using `test_copy_bytes()` to copy the first N bytes.\n\nIt would be conceptually more elegant to teach `genrandom` to optionally\noutput only lower-case letters. But that would be admittedly result in a\nlarger patch, therefore I am okay with keeping the patch as-is.\n\nCiao,\nJohannes\n\n>\n> This allows us to drop the PERL_TEST_HELPERS prerequisite.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/t0021-conversion.sh | 7 +++----\n>  1 file changed, 3 insertions(+), 4 deletions(-)\n>\n> diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\n> index 4a892a91780..bf10d253ec4 100755\n> --- a/t/t0021-conversion.sh\n> +++ b/t/t0021-conversion.sh\n> @@ -20,8 +20,7 @@ EOF\n>  generate_random_characters () {\n>  \tLEN=$1\n>  \tNAME=$2\n> -\ttest-tool genrandom some-seed $LEN |\n> -\t\tperl -pe \"s/./chr((ord($&) % 26) + ord('a'))/sge\" >\"$TEST_ROOT/$NAME\"\n> +\ttest-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes \"$LEN\" >\"$TEST_ROOT/$NAME\"\n>  }\n>\n>  filter_git () {\n> @@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n>  \t)\n>  '\n>\n> -test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n> +test_expect_success 'required process filter should process multiple packets' '\n>  \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n>  \ttest_config_global filter.protocol.required true &&\n>\n> @@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu\n>  \t)\n>  '\n>\n> -test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n> +test_expect_success 'required process filter with clean error should fail' '\n>  \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n>  \ttest_config_global filter.protocol.required true &&\n>  \trm -rf repo &&\n>\n> --\n> 2.49.0.472.ge94155a9ec.dirty\n>\n>\n"},{"id":"515478","messageId":"Z-zkOFD8PRS4L7Ed@pks.im","threadId":"63168","inReplyTo":"4d461a62-9cf5-c64d-cd97-c70ef53afbac@gmx.de","subject":"Re: [PATCH v3 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:08Z","receivedAt":"2025-04-02T07:16:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 08:35:25PM +0200, Johannes Schindelin wrote:\n> Hi Patrick,\n> \n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> \n> > A bunch of tests rely on Perl to print data in various different ways.\n> > These usages fall into the following categories:\n> >\n> >   - Print data conditionally by matching patterns. These usecases can be\n> >     converted to use awk(1) rather easily.\n> >\n> >   - Print data repeatedly. These usecases can typically be converted to\n> >     use a combination of `test-tool genzeros` and sed(1).\n> \n> It might be even more elegant to teach `genzeros` to generate streams of\n> bytes other than NUL.\n\nAgreed, that would feel more elegant indeed (well, despite the name\nbeing inaccurate now). I decided against doing this so that we don't\nhave to introduce too many tools, but wouldn't mind doing so if you or\nother people feel strongly about it.\n\n> >   - Print data in reverse. These usecases can be converted to use\n> >     awk(1).\n> \n> Or, in one case, `sort -r`.\n\nTrue, fixed.\n\nPatrick\n"},{"id":"515479","messageId":"Z-zkP7T-0zyW7HAc@pks.im","threadId":"63168","inReplyTo":"92fd1e8b-4790-0c81-409a-be81aed9f290@gmx.de","subject":"Re: [PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:15Z","receivedAt":"2025-04-02T07:16:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 09:04:44PM +0200, Johannes Schindelin wrote:\n> Hi Patrick,\n> \n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> \n> > The `generate_random_characters()` helper function generates N\n> > random characters in the range 'a-z' and writes them into a file. The\n> > logic currently uses Perl, but it can be adapted rather easily by:\n> >\n> >   - Making `test-tool genrandom` generate an infinite stream.\n> >\n> >   - Using `tr -dc` to strip all characters which aren't in the range of\n> >     'a-z'.\n> >\n> >   - Using `test_copy_bytes()` to copy the first N bytes.\n> \n> It would be conceptually more elegant to teach `genrandom` to optionally\n> output only lower-case letters. But that would be admittedly result in a\n> larger patch, therefore I am okay with keeping the patch as-is.\n\nYeah, it's basically the same reason why I decided against teaching\n`test-tool genzeros` to output arbitrary characters. And again, I'm\nhappy to adapt if anybody feels strongly, but meanwhile I'm being\npragmatic and go with the simple solution.\n\nPatrick\n"},{"id":"515480","messageId":"Z-zkQyRCM3BkovgY@pks.im","threadId":"63168","inReplyTo":"ee5e082f-6ab5-b996-9a0d-f7e5192c01be@gmx.de","subject":"Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:19Z","receivedAt":"2025-04-02T07:16:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:\n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> \n> > In the early days of Git, Perl was used quite prominently throughout the\n> > project. This has changed significantly as almost all of the executables\n> > we ship nowadays have eventually been rewritten in C. Only a handful of\n> > subsystems remain that require Perl:\n> >\n> >   - gitweb, a read-only web interface.\n> >\n> >   - A couple of scripts that allow importing repositories from GNU Arch,\n> >     CVS and Subversion.\n> >\n> >   - git-send-email(1), which can be used to send mails.\n> \n> There is also `git request-pull` which is a _shell_ script that runs\n> `perl` to parse the output of `ls-remote`, and there is `git\n> filter-branch` (which was apparently not yet dropped?) that uses Perl if\n> the `--state-branch` option is in use.\n\nAh, indeed, thanks!\n\nI should probably mark both of these to require Perl in our build\nsystems so that we have a source of truth what requires Perl and what\ndoesn't. git-filter-branch(1) also looks somewhat broken because it uses\nPerl directly instead of using PERL_PATH.\n\nOn the other hand, maybe the better fix would be to just convert tools\nto not use Perl at all anymore so that we can eventually get rid of this\ndependency altogether. It feels like we're quite close, and many of\nthese conversions are low-hanging fruit.\n\n> The patch looks good, in particular when fetching the `b4/pks-t-perlless`\n> branch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f\n> manually, as it is a rather large patch that is pretty much unreviewable\n> on a mailing list.\n> \n> Using several write-only `sed` invocations, I identified that there are\n> only three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`\n> prereq nor adding a test preamble of this form:\n> \n> \tif ! test_have_prereq PERL_TEST_HELPERS\n> \tthen\n> \t\tskip_all='skipping <something>; Perl not available'\n> \t\ttest_done\n> \tfi\n\nThanks for double checking!\n\nPatrick\n"},{"id":"515481","messageId":"Z-zkR_9CCVA57wKV@pks.im","threadId":"63168","inReplyTo":"70026fe9-8c99-ab00-531f-1556db63b0d8@gmx.de","subject":"Re: [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:23Z","receivedAt":"2025-04-02T07:16:27Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 08:32:02PM +0200, Johannes Schindelin wrote:\n> Hi Patrick,\n> \n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> \n> > We have a bunch of tests that use Perl to perform substitution via the\n> > \"s/\" operator. These usecases can be trivially replaced with sed(1).\n> \n> ... and sometimes `tr`.\n> \n> In fact, it looks like...\n> \n> > diff --git a/t/t7508-status.sh b/t/t7508-status.sh\n> > index 14c41b2cb7c..cdc1d6fcc78 100755\n> > --- a/t/t7508-status.sh\n> > +++ b/t/t7508-status.sh\n> > @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n> >  \ttest_cmp expect output\n> >  '\n> >\n> > -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n> > +test_expect_success 'status -z implies porcelain' '\n> >  \tgit status --porcelain |\n> > -\tperl -pe \"s/\\012/\\000/g\" >expect &&\n> > +\ttr \"\\012\" \"\\000\" >expect &&\n> >  \tgit status -z >output &&\n> >  \ttest_cmp expect output\n> >  '\n> \n> ... this change is not about `sed` at all, but only about `tr`.\n> _Technically_, this hunk would therefore feel more at home in the previous\n> patch. But practically, I actually do not mind it being here at all.\n\nYeah, the boundaries between commits are fuzzy at times. I mostly wanted\nto split up similar changes so that the review load is somewhat\nreasonable and not have a single patch that does it all at once. And\nthis site here did use Perl's substitution operator, so it's not wrong\nper se that we do the conversion as part of this patch. But it's of\ncourse wrong that I only mention sed(1) in the commit message.\n\nPatrick\n"},{"id":"515482","messageId":"Z-zkSpKsvEYWw4Pr@pks.im","threadId":"63168","inReplyTo":"c909b89f-7432-2d35-cfdb-0de9f94a7281@gmx.de","subject":"Re: [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:26Z","receivedAt":"2025-04-02T07:16:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 08:56:41PM +0200, Johannes Schindelin wrote:\n> \n> Hi Patrick,\n> \n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> \n> > The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\n> > stdin. Refactor it to instead use awk(1) so that we drop the\n> > PERL_TEST_HELPERS prerequisite in users of this library.\n> \n> It's my fault that this commit message is no longer correct because I\n> talked you into using `sed` instead...\n> \n> Sorry,\n> Johannes\n\nNo need to be sorry, should've catched that myself :) Thanks for the\nsuggestion in the first place, it made the new logic quite a bit easier\nto read!\n\nPatrick\n"},{"id":"515483","messageId":"Z-zkVL8cSYEiR_T1@pks.im","threadId":"63168","inReplyTo":"9f477166-5667-a051-13d3-43d56a7a8ec1@gmx.de","subject":"Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-02T07:16:36Z","receivedAt":"2025-04-02T07:16:40Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Apr 01, 2025 at 08:55:22PM +0200, Johannes Schindelin wrote:\n> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> > diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\n> > index c7d8eb12453..f904fc19f69 100755\n> > --- a/t/t4030-diff-textconv.sh\n> > +++ b/t/t4030-diff-textconv.sh\n> > @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n> >  +1\n> >  EOF\n> >\n> > -cat >hexdump <<'EOF'\n> > -#!/bin/sh\n> > -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> > -EOF\n> > -chmod +x hexdump\n> > -\n> >  test_expect_success 'setup binary file with history' '\n> > +\twrite_script hexdump <<-\\EOF &&\n> > +\ttr \"\\000\\001\" \"01\" <\"$1\"\n> > +\tEOF\n> \n> So here the `hexdump` script is written, basically replacing NUL and SOH\n> with the digits zero and one, respectively. I wonder why the script does\n> not call `test-tool hexdump` instead? And I wonder even more why no test\n> case has to be adapted below this change in the same file. I _guess_ that\n> the reason is that the file named, creatively, \"file\" is initialized with\n> a NUL and a newline, committed, then a line is appended that contains SOH\n> and a newline, and then the test cases verify the hunk _headers_ only?\n> \n> If using `test-tool hexdump <\"$1\"` would work here, too, I'd actually have\n> preferred that over the `tr` invocation, even if would still not be\n> recapitulating the functionality of that Perl script (which, contrary to\n> its name, seemed never to have output hexadecimal values...).\n> \n> To be clear: I do not suggest to change the patch, I am merely puzzled why\n> the more obvious `test-tool hexdump <\"$1\"` was not used here?\n\nPhillip had the same comment, and I was trying to address that by\nimproving the commit message a bit. But seems like it still isn't clear\nenough.\n\nThe reason why I decided against using `test-tool hexdump` is that it\nwould have a ripple effect. The output generated by that helper is not\nthe same as the output generated by the Perl script, so if we started to\nuse the hexdump helper I would have to adapt a bunch of tests in this\ntest file to update their expectations.\n\nThe result would look something like the appended patch, which I think\nis quite awkward. On the one hand we have trailing whitespace in the\nexpectation, on the other hand we have weird seemingly-unrelated changes\nin other tests. So I shied away from that and instead decided to use a\nsimpler variant of the textconv script.\n\nLet me adapt the commit message once again and make it a bit more\nconcrete compared to the current fuzzy description.\n\nPatrick\n\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex f904fc19f69..16d7fd4c5ca 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -15,14 +15,14 @@ EOF\n cat >expect.text <<'EOF'\n --- a/file\n +++ b/file\n-@@ -1 +1,2 @@\n- 0\n-+1\n+@@ -1 +1 @@\n+-00 0a \n++00 0a 01 0a \n EOF\n \n test_expect_success 'setup binary file with history' '\n \twrite_script hexdump <<-\\EOF &&\n-\ttr \"\\000\\001\" \"01\" <\"$1\"\n+\ttest-tool hexdump <\"$1\"\n \tEOF\n \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n@@ -92,7 +92,7 @@ test_expect_success 'show blob produces binary' '\n \n test_expect_success 'show --textconv blob produces text' '\n \tgit show --textconv HEAD:file >actual &&\n-\tprintf \"0\\\\n1\\\\n\" >expect &&\n+\tprintf \"00 0a 01 0a \\n\" >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -103,7 +103,7 @@ test_expect_success 'show --no-textconv blob produces binary' '\n '\n \n test_expect_success 'grep-diff (-G) operates on textconv data (add)' '\n-\techo one >expect &&\n+\tprintf \"two\\none\\n\" >expect &&\n \tgit log --root --format=%s -G0 >actual &&\n \ttest_cmp expect actual\n '\n@@ -115,7 +115,7 @@ test_expect_success 'grep-diff (-G) operates on textconv data (modification)' '\n '\n \n test_expect_success 'pickaxe (-S) operates on textconv data (add)' '\n-\techo one >expect &&\n+\tprintf \"two\\none\\n\" >expect &&\n \tgit log --root --format=%s -S0 >actual &&\n \ttest_cmp expect actual\n '\n@@ -146,9 +146,8 @@ symlink=$(git rev-parse --short $(printf frotz | git hash-object --stdin))\n cat >expect.typechange <<EOF\n --- a/file\n +++ /dev/null\n-@@ -1,2 +0,0 @@\n--0\n--1\n+@@ -1 +0,0 @@\n+-00 0a 01 0a \n diff --git a/file b/file\n new file mode 120000\n index 0000000..$symlink\n"},{"id":"515528","messageId":"5a344739-6556-858f-8769-c42e48f01a6f@gmx.de","threadId":"63168","inReplyTo":"Z-zkQyRCM3BkovgY@pks.im","subject":"Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-02T19:10:16Z","receivedAt":"2025-04-02T19:10:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Wed, 2 Apr 2025, Patrick Steinhardt wrote:\n\n> On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:\n> > On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> >\n> > > In the early days of Git, Perl was used quite prominently throughout\n> > > the project. This has changed significantly as almost all of the\n> > > executables we ship nowadays have eventually been rewritten in C.\n> > > Only a handful of subsystems remain that require Perl:\n> > >\n> > >   - gitweb, a read-only web interface.\n> > >\n> > >   - A couple of scripts that allow importing repositories from GNU Arch,\n> > >     CVS and Subversion.\n> > >\n> > >   - git-send-email(1), which can be used to send mails.\n> >\n> > There is also `git request-pull` which is a _shell_ script that runs\n> > `perl` to parse the output of `ls-remote`, and there is `git\n> > filter-branch` (which was apparently not yet dropped?) that uses Perl if\n> > the `--state-branch` option is in use.\n>\n> Ah, indeed, thanks!\n>\n> I should probably mark both of these to require Perl in our build\n> systems so that we have a source of truth what requires Perl and what\n> doesn't. git-filter-branch(1) also looks somewhat broken because it uses\n> Perl directly instead of using PERL_PATH.\n\nTrue.\n\n> On the other hand, maybe the better fix would be to just convert tools\n> to not use Perl at all anymore so that we can eventually get rid of this\n> dependency altogether. It feels like we're quite close, and many of\n> these conversions are low-hanging fruit.\n\nAs for `git filter-branch`, we could simply -- what were the wise words of\nElijah's mentor? -- \"debug\" it. I.e. delete it and be happy about it.\n\n> > The patch looks good, in particular when fetching the `b4/pks-t-perlless`\n> > branch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f\n> > manually, as it is a rather large patch that is pretty much unreviewable\n> > on a mailing list.\n> >\n> > Using several write-only `sed` invocations, I identified that there are\n> > only three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`\n> > prereq nor adding a test preamble of this form:\n> >\n> > \tif ! test_have_prereq PERL_TEST_HELPERS\n> > \tthen\n> > \t\tskip_all='skipping <something>; Perl not available'\n> > \t\ttest_done\n> > \tfi\n>\n> Thanks for double checking!\n\nYou're welcome. I am a bit embarrassed to admit that it took me quite a\nbit of time, I believe it was around an hour, to validate this patch\nalone.\n\nCiao,\nJohannes\n"},{"id":"515529","messageId":"62c3f77c-32f4-8c24-560d-24fac9b2e807@gmx.de","threadId":"63168","inReplyTo":"Z-zkVL8cSYEiR_T1@pks.im","subject":"Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-02T19:17:14Z","receivedAt":"2025-04-02T19:17:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Wed, 2 Apr 2025, Patrick Steinhardt wrote:\n\n> On Tue, Apr 01, 2025 at 08:55:22PM +0200, Johannes Schindelin wrote:\n> > On Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n> > > diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\n> > > index c7d8eb12453..f904fc19f69 100755\n> > > --- a/t/t4030-diff-textconv.sh\n> > > +++ b/t/t4030-diff-textconv.sh\n> > > @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n> > >  +1\n> > >  EOF\n> > >\n> > > -cat >hexdump <<'EOF'\n> > > -#!/bin/sh\n> > > -\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n> > > -EOF\n> > > -chmod +x hexdump\n> > > -\n> > >  test_expect_success 'setup binary file with history' '\n> > > +\twrite_script hexdump <<-\\EOF &&\n> > > +\ttr \"\\000\\001\" \"01\" <\"$1\"\n> > > +\tEOF\n> >\n> > So here the `hexdump` script is written, basically replacing NUL and SOH\n> > with the digits zero and one, respectively. I wonder why the script does\n> > not call `test-tool hexdump` instead? And I wonder even more why no test\n> > case has to be adapted below this change in the same file. I _guess_ that\n> > the reason is that the file named, creatively, \"file\" is initialized with\n> > a NUL and a newline, committed, then a line is appended that contains SOH\n> > and a newline, and then the test cases verify the hunk _headers_ only?\n> >\n> > If using `test-tool hexdump <\"$1\"` would work here, too, I'd actually have\n> > preferred that over the `tr` invocation, even if would still not be\n> > recapitulating the functionality of that Perl script (which, contrary to\n> > its name, seemed never to have output hexadecimal values...).\n> >\n> > To be clear: I do not suggest to change the patch, I am merely puzzled why\n> > the more obvious `test-tool hexdump <\"$1\"` was not used here?\n>\n> Phillip had the same comment, and I was trying to address that by\n> improving the commit message a bit. But seems like it still isn't clear\n> enough.\n\nOr I am too slow, that's also a possibility.\n\n> The reason why I decided against using `test-tool hexdump` is that it\n> would have a ripple effect. The output generated by that helper is not\n> the same as the output generated by the Perl script, so if we started to\n> use the hexdump helper I would have to adapt a bunch of tests in this\n> test file to update their expectations.\n>\n> The result would look something like the appended patch, which I think\n> is quite awkward. On the one hand we have trailing whitespace in the\n> expectation, on the other hand we have weird seemingly-unrelated changes\n> in other tests. So I shied away from that and instead decided to use a\n> simpler variant of the textconv script.\n\nThat makes sense. Not only would it be a chattier diff, it would be even\nharder to validate. I would probably have written an entire paragraph in the\ncommit message just about this decision, if only to get frustration about\nthe state of Git's tests off of my chest. Your decision to avoid spending\nmore energy on this than you already did sounds like a smart one to me,\nand I am sorry that I forced you to explain this one more time.\n\n> Let me adapt the commit message once again and make it a bit more\n> concrete compared to the current fuzzy description.\n\nYour explanation is sufficient for me, therefore you do not need to send\nanother iteration merely for my sake.\n\nThank you,\nJohannes\n\n"},{"id":"515530","messageId":"4d87ad16-3995-1dca-7440-6aa6b26063d8@gmx.de","threadId":"63168","inReplyTo":"20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im","subject":"Re: [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-02T19:32:10Z","receivedAt":"2025-04-02T19:32:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 27 Mar 2025, Patrick Steinhardt wrote:\n\n> while Git was initially building on Perl quite a lot, the significance\n> of Perl has been dwindling over the years as more and more functionality\n> was converted into C builtins. Nowadays, an installation with Perl-based\n> features disabled is almost fully functional, only a handful of features\n> remain that require Perl:\n>\n>   - gitweb, a read-only web interface.\n>\n>   - A couple of scripts that allow importing repositories from GNU Arch,\n>     CVS and Subversion.\n>\n>   - git-send-email(1), which can be used to send mails.\n>\n>   - Our Perl bindings for Git.\n>\n>   - The netrc Git credential helper.\n>\n> None of these features really are critical for day-to-day usage of Git,\n> and most users probably wouldn't even notice if those features were not\n> installed. Perl is thus very much optional nowadays.\n>\n> There is one big exception though: it is impossible to run our test\n> suite without a Perl interpreter, so it is not easily possible to verify\n> that a Perl-less installation actually works as expected. For most of\n> the part though our test suite doesn't use all that much Perl, either.\n> It is present in a couple of critical paths, but those are easy to adapt\n> to not use Perl anymore.\n>\n> This is exactly what this patch series does: it refactors a couple of\n> central parts in our test suite to not use Perl anymore so that it\n> becomes possible to run most of our tests entirely without Perl. Tests\n> that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq\n> so that they only execute when a Perl interpreter is available.\n>\n> With this patch series, 30342 out of 31358 tests pass, which is around\n> 97% of our tests.\n\nThank you so much for working on this. I finally finished my review, I\nsimply ran out of time yesterday. The patches look good to me, and the\nresult even more so.\n\nFrom my perspective, it also sure looks like good timing, even so much as\ntwo years ago it would probably not have been realistically achievable to\ndrop Git's test suite's dependency on Perl.\n\nOn Git for Windows' side, I have opened a ticket [*1*] that even discusses\nthe idea of dropping Perl from Git for Windows' installer altogether. The\nappeal of this is that Perl is quite a hefty dependency with all of those\nPerl modules that are part of the set that Perl users simply expect to be\npresent. I did not investigate this fully yet, but would expect a\nreduction of at least 10MB, and Git for Windows carries this essentially\nfor `git svn` and little else.\n\nSo yes, I am quite happy about this direction, and could also imagine that\nat least the Windows test jobs (which use `prove` like the rest of the\ntests in Git's CI builds) could potentially switch away from `prove` to\n`test-tool run-command testsuite` and then drop Perl from the\n`git-sdk-x86_64-minimal` artifact that needs to be downloaded and\ninstalled for every single Windows job of Git's CI. (The `test-tool` may\nneed to learn a few more tricks, but I'd be surprised if any non-trivial\npatches were needed there to essentially replace `prove` as far as Git's\nneeds are concerned.)\n\nCiao,\nJohannes\n\nFootnote *1*: https://github.com/git-for-windows/git/issues/5393\n"},{"id":"515544","messageId":"Z-4XBk6RrHirISYE@pks.im","threadId":"63168","inReplyTo":"5a344739-6556-858f-8769-c42e48f01a6f@gmx.de","subject":"Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:10Z","receivedAt":"2025-04-03T05:05:20Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Apr 02, 2025 at 09:10:16PM +0200, Johannes Schindelin wrote:\n> On Wed, 2 Apr 2025, Patrick Steinhardt wrote:\n> > On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:\n> > On the other hand, maybe the better fix would be to just convert tools\n> > to not use Perl at all anymore so that we can eventually get rid of this\n> > dependency altogether. It feels like we're quite close, and many of\n> > these conversions are low-hanging fruit.\n> \n> As for `git filter-branch`, we could simply -- what were the wise words of\n> Elijah's mentor? -- \"debug\" it. I.e. delete it and be happy about it.\n\nI wouldn't mind it, but we should probably have a proper replacement for\nit first. Ideally in the form of git-filter-repo(1) being part of Git\nitself.\n\nIn any case, meanwhile I have created a follow-up patch series that\nadapts both git-filter-branch(1) and git-request-pull(1) to not require\nPerl anymore.\n\nPatrick\n"},{"id":"515545","messageId":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im","subject":"[PATCH v4 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:51Z","receivedAt":"2025-04-03T05:05:58Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nwhile Git was initially building on Perl quite a lot, the significance\nof Perl has been dwindling over the years as more and more functionality\nwas converted into C builtins. Nowadays, an installation with Perl-based\nfeatures disabled is almost fully functional, only a handful of features\nremain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these features really are critical for day-to-day usage of Git,\nand most users probably wouldn't even notice if those features were not\ninstalled. Perl is thus very much optional nowadays.\n\nThere is one big exception though: it is impossible to run our test\nsuite without a Perl interpreter, so it is not easily possible to verify\nthat a Perl-less installation actually works as expected. For most of\nthe part though our test suite doesn't use all that much Perl, either.\nIt is present in a couple of critical paths, but those are easy to adapt\nto not use Perl anymore.\n\nThis is exactly what this patch series does: it refactors a couple of\ncentral parts in our test suite to not use Perl anymore so that it\nbecomes possible to run most of our tests entirely without Perl. Tests\nthat still depend on Perl are marked with a new PERL_TEST_HELPERS prereq\nso that they only execute when a Perl interpreter is available.\n\nWith this patch series, 30342 out of 31358 tests pass, which is around\n97% of our tests.\n\nChanges in v2:\n  - Improve a couple of conversions based on feedback.\n  - Clarify the commit message of the textconv conversion.\n  - Fix a copy-paste error when it comes to skipping tests in t4103.\n  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im\n\nChanges in v3:\n  - Remove more useless indirections for sed(1).\n  - Link to v2: https://lore.kernel.org/r/20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im\n\nChanges in v4:\n  - Improve a couple of commit messages to better explain the changes.\n  - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (20):\n      t: skip chain lint when PERL_PATH is unset\n      t: refactor environment sanitization to not use Perl\n      t: adapt character translation helpers to not use Perl\n      t: adapt `test_copy_bytes()` to not use Perl\n      t: adapt `test_readlink()` to not use Perl\n      t: introduce PERL_TEST_HELPERS prerequisite\n      t: adapt existing PERL prerequisites\n      meson: stop requiring Perl when tests are enabled\n      Makefile: stop requiring Perl when running tests\n      t: refactor tests depending on Perl transliteration operator\n      t: refactor tests depending on Perl substitution operator\n      t: refactor tests depending on Perl to print data\n      t: refactor tests depending on Perl for textconv scripts\n      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n      t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n      t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n      t0021: refactor `generate_random_characters()` to not depend on Perl\n      t0210: refactor trace2 scrubbing to not use Perl\n      t5316: refactor `max_chain()` to not depend on Perl\n      t5703: refactor test to not depend on Perl\n\n meson.build                               |  2 +-\n t/Makefile                                | 16 +++++++--\n t/helper/test-path-utils.c                | 13 ++++++++\n t/helper/test-sha1.sh                     |  4 +--\n t/lib-diff.sh                             |  4 +--\n t/lib-gpg.sh                              |  6 +---\n t/lib-httpd.sh                            |  2 +-\n t/lib-httpd/apache.conf                   |  6 ++--\n t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------\n t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++\n t/lib-t6000.sh                            | 13 ++++----\n t/t0008-ignores.sh                        |  4 +--\n t/t0021-conversion.sh                     | 13 ++++----\n t/t0090-cache-tree.sh                     |  4 +--\n t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------\n t/t0210/scrub_normal.perl                 | 54 ------------------------------\n t/t0211-trace2-perf.sh                    |  6 ++++\n t/t0610-reftable-basics.sh                |  5 ++-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       | 16 +++++----\n t/t1007-hash-object.sh                    |  6 ++--\n t/t1010-mktree.sh                         |  4 +--\n t/t1450-fsck.sh                           |  6 ++--\n t/t3300-funny-names.sh                    |  6 ++--\n t/t4013-diff-various.sh                   |  6 ++++\n t/t4014-format-patch.sh                   | 30 ++++++++---------\n t/t4020-diff-external.sh                  |  2 +-\n t/t4029-diff-trailing-space.sh            |  3 +-\n t/t4030-diff-textconv.sh                  |  9 ++---\n t/t4031-diff-rewrite-binary.sh            | 17 ++++------\n t/t4058-diff-duplicates.sh                |  6 ++++\n t/t4103-apply-binary.sh                   |  6 ++--\n t/t4116-apply-reverse.sh                  |  4 +--\n t/t4150-am.sh                             |  8 ++---\n t/t4200-rerere.sh                         |  8 ++---\n t/t4205-log-pretty-formats.sh             |  6 ++--\n t/t4216-log-bloom.sh                      |  8 ++---\n t/t5004-archive-corner-cases.sh           |  6 ++++\n t/t5300-pack-object.sh                    | 10 +++---\n t/t5303-pack-corruption-resilience.sh     |  6 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               | 10 +++---\n t/t5318-commit-graph.sh                   | 12 +++----\n t/t5319-multi-pack-index.sh               | 16 ++++-----\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  4 +--\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  2 +-\n t/t5503-tagfollow.sh                      |  6 ++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++\n t/t5532-fetch-proxy.sh                    |  6 ++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  | 15 ++++-----\n t/t5551-http-fetch-smart.sh               |  7 ++++\n t/t5562-http-backend-content-length.sh    |  6 ++++\n t/t5601-clone.sh                          |  4 +--\n t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------\n t/t5701-git-serve.sh                      |  5 ++-\n t/t5702-protocol-v2.sh                    | 21 +++++++-----\n t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------\n t/t5710-promisor-remote-capability.sh     |  6 ++++\n t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---\n t/t6013-rev-list-reverse-parents.sh       | 10 +++---\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++\n t/t6115-rev-list-du.sh                    |  2 +-\n t/t6300-for-each-ref.sh                   | 15 ++++++---\n t/t7006-pager.sh                          |  6 ++--\n t/t7416-submodule-dash-url.sh             |  3 +-\n t/t7501-commit-basic-functionality.sh     |  6 ++--\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  9 ++---\n t/t8001-annotate.sh                       |  6 ++++\n t/t8002-blame.sh                          |  8 ++++-\n t/t8006-blame-textconv.sh                 |  2 +-\n t/t8011-blame-split-file.sh               |  6 ++--\n t/t8012-blame-colors.sh                   |  6 ++++\n t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib-functions.sh                   | 20 +++--------\n t/test-lib.sh                             | 49 +++++++++++++++++----------\n 84 files changed, 471 insertions(+), 373 deletions(-)\n\nRange-diff versus v3:\n\n 1:  9a500263cea =  1:  cd553f570b7 t: skip chain lint when PERL_PATH is unset\n 2:  3cc409f35ab =  2:  bd2b95c2fa5 t: refactor environment sanitization to not use Perl\n 3:  46bba778281 =  3:  81b99adaf5b t: adapt character translation helpers to not use Perl\n 4:  72f65ee6f3d =  4:  ef624217370 t: adapt `test_copy_bytes()` to not use Perl\n 5:  57b4e5e0b2c =  5:  4e6c4b654f5 t: adapt `test_readlink()` to not use Perl\n 6:  61230a9f7e5 !  6:  cbefcec77f9 t: introduce PERL_TEST_HELPERS prerequisite\n    @@ Commit message\n     \n           - git-send-email(1), which can be used to send mails.\n     \n    +      - git-request-pull(1), which is used to request somebody to pull from\n    +        a URL by sending an email.\n    +\n    +      - git-filter-branch(1), which uses Perl with the `--state-branch`\n    +        option. This command is typically recommended against nowadays in\n    +        favor of git-filter-repo(1).\n    +\n           - Our Perl bindings for Git.\n     \n           - The netrc Git credential helper.\n 7:  37a944f2295 =  7:  8d08fe26be3 t: adapt existing PERL prerequisites\n 8:  58513ff9510 =  8:  c4451024f2d meson: stop requiring Perl when tests are enabled\n 9:  68cdf732fe7 =  9:  2d3c3d10c00 Makefile: stop requiring Perl when running tests\n10:  acba0e69f8f = 10:  25737787f61 t: refactor tests depending on Perl transliteration operator\n11:  888b283db98 ! 11:  863e029c0d3 t: refactor tests depending on Perl substitution operator\n    @@ Commit message\n         t: refactor tests depending on Perl substitution operator\n     \n         We have a bunch of tests that use Perl to perform substitution via the\n    -    \"s/\" operator. These usecases can be trivially replaced with sed(1).\n    +    \"s/\" operator. These usecases can be trivially replaced with sed(1) and\n    +    tr(1).\n     \n         Refactor the tests accordingly so that we can drop a couple of\n         PERL_TEST_HELPERS prerequisites.\n12:  e2fbbad39e3 ! 12:  ba13f633705 t: refactor tests depending on Perl to print data\n    @@ Commit message\n             use a combination of `test-tool genzeros` and sed(1).\n     \n           - Print data in reverse. These usecases can be converted to use\n    -        awk(1).\n    +        awk(1) or `sort -r`.\n     \n         Refactor the tests accordingly so that we can drop a couple of\n         PERL_TEST_HELPERS prerequisites.\n13:  12950479b79 ! 13:  80bda885e4d t: refactor tests depending on Perl for textconv scripts\n    @@ Commit message\n         Refactor these tests to instead be implemented via shell utilities so\n         that we can drop a couple of PERL_TEST_HELPERS prerequisites.\n     \n    -    Note that not all of the conversions are a one-to-one equivalent to the\n    -    previous textconv scripts. But that's not really needed in the first\n    -    place: we only care that the textconv script does something, and that\n    -    can be verified trivially without having a full-blown invocation of\n    -    hexdump. So at times, the implementation of the textconv scripts is\n    -    reduced to their bare minimum and the expectations of those tests are\n    -    adapted accordingly.\n    +    Note that the conversion in t4030 is not a one-to-one equivalent to the\n    +    previous textconv script. Before this change we used to essentially do a\n    +    hexdump via Perl. The obvious conversion here would be to use `test-tool\n    +    hexdump` like we do for the other tests. But this would lead to a ripple\n    +    effect where we would have to adapt a bunch of other tests with a bunch\n    +    of seemingly unrelated changes, which would be somewhat awkward.\n    +\n    +    Instead, we're going with the minimum viable change: the test files we\n    +    write contain \"\\001\" and \"\\000\", and the test's expectation is that\n    +    those get translated into proper ASCII characters. So instead of doing a\n    +    full hexdump, we simply use tr(1) to translate these specific bytes.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n14:  e3fe9e7292f ! 14:  da8e5e89029 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n    @@ Commit message\n         t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl\n     \n         The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\n    -    stdin. Refactor it to instead use awk(1) so that we drop the\n    +    stdin. Refactor it to instead use sed(1) so that we drop the\n         PERL_TEST_HELPERS prerequisite in users of this library.\n     \n         Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\n15:  8c180723c5d = 15:  98afe2b4f71 t/lib-t6000: refactor `name_from_description()` to not depend on Perl\n16:  9e5d5fc4d57 = 16:  a7d26d221cb t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl\n17:  4e5431788b0 = 17:  4b36ae2a602 t0021: refactor `generate_random_characters()` to not depend on Perl\n18:  f7fd16661ca = 18:  27c720a3952 t0210: refactor trace2 scrubbing to not use Perl\n19:  ee8d1bed611 = 19:  e08ed2f2c64 t5316: refactor `max_chain()` to not depend on Perl\n20:  740009a2d0c = 20:  710158c13a7 t5703: refactor test to not depend on Perl\n\n---\nbase-commit: 683c54c999c301c2cd6f715c411407c413b1d84e\nchange-id: 20250317-b4-pks-t-perlless-138cf94696b8\n\n"},{"id":"515546","messageId":"20250403-b4-pks-t-perlless-v4-1-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:52Z","receivedAt":"2025-04-03T05:05:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our chainlint script verifies that test files have proper '&&' chains.\nThis script is written in Perl and executed for every test file before\nexecuting the test logic itself.\n\nIn subsequent commits we're about to refactor our test suite so that\nPerl becomes an optional dependency, only. And while it is already\npossible to disable this linter, developers that don't have Perl\navailable at all would always have to disable the linter manually, which\nis rather cumbersome.\n\nDisable the chain linter automatically in case PERL_PATH isn't set to\nmake this a bit less annoying. Bail out with an error in case the\ndeveloper has asked explicitly for the chain linter.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 9001ed3a647..1ce3b32fcac 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1523,6 +1523,22 @@ then\n \texport LSAN_OPTIONS\n fi\n \n+if test -z \"$PERL_PATH\"\n+then\n+\tcase \"${GIT_TEST_CHAIN_LINT:-unset}\" in\n+\tunset)\n+\t\tGIT_TEST_CHAIN_LINT=0\n+\t\t;;\n+\t0)\n+\t\t# The user has explicitly disabled the chain linter, so we\n+\t\t# don't have anything to worry about.\n+\t\t;;\n+\t*)\n+\t\tBAIL_OUT 'You need Perl for the chain linter'\n+\t\t;;\n+\tesac\n+fi\n+\n if test \"${GIT_TEST_CHAIN_LINT:-1}\" != 0 &&\n    test \"${GIT_TEST_EXT_CHAIN_LINT:-1}\" != 0\n then\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515547","messageId":"20250403-b4-pks-t-perlless-v4-2-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 02/20] t: refactor environment sanitization to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:53Z","receivedAt":"2025-04-03T05:06:01Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Before executing tests we first sanitize the environment. Part of the\nsanitization is to unset a couple of environment variables that we know\nwill change the behaviour of Git. This is done with a small Perl script,\nwhich has the consequence that having a Perl interpreter available is a\nstrict requirement for running our unit tests.\n\nThe logic itself isn't particularly involved: we simply unset every\nenvironment variable whose key starts with 'GIT_', but then explicitly\nallow a subset of these.\n\nRefactor the logic to instead use sed(1) so that it becomes possible to\nexecute our tests without Perl.\n\nBased-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib.sh | 32 ++++++++++++++------------------\n 1 file changed, 14 insertions(+), 18 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 1ce3b32fcac..a62699d6c79 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -499,24 +499,20 @@ EDITOR=:\n # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets\n # deriving from the command substitution clustered with the other\n # ones.\n-unset VISUAL EMAIL LANGUAGE $(\"$PERL_PATH\" -e '\n-\tmy @env = keys %ENV;\n-\tmy $ok = join(\"|\", qw(\n-\t\tTRACE\n-\t\tDEBUG\n-\t\tTEST\n-\t\t.*_TEST\n-\t\tPROVE\n-\t\tVALGRIND\n-\t\tUNZIP\n-\t\tPERF_\n-\t\tCURL_VERBOSE\n-\t\tTRACE_CURL\n-\t\tBUILD_DIR\n-\t));\n-\tmy @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);\n-\tprint join(\"\\n\", @vars);\n-')\n+unset VISUAL EMAIL LANGUAGE $(env | sed -n \\\n+\t-e '/^GIT_TRACE/d' \\\n+\t-e '/^GIT_DEBUG/d' \\\n+\t-e '/^GIT_TEST/d' \\\n+\t-e '/^GIT_.*_TEST/d' \\\n+\t-e '/^GIT_PROVE/d' \\\n+\t-e '/^GIT_VALGRIND/d' \\\n+\t-e '/^GIT_UNZIP/d' \\\n+\t-e '/^GIT_PERF_/d' \\\n+\t-e '/^GIT_CURL_VERBOSE/d' \\\n+\t-e '/^GIT_TRACE_CURL/d' \\\n+\t-e '/^GIT_BUILD_DIR/d' \\\n+\t-e 's/^\\(GIT_[^=]*\\)=.*/\\1/p'\n+)\n unset XDG_CACHE_HOME\n unset XDG_CONFIG_HOME\n unset GITPERLLIB\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515548","messageId":"20250403-b4-pks-t-perlless-v4-3-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 03/20] t: adapt character translation helpers to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:54Z","receivedAt":"2025-04-03T05:06:03Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of helper functions that translate characters, e.g.\nfrom LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl\nscripts, but they can be trivially adapted to instead use tr(1).\n\nNote that one specialty here is the handling of NUL characters in tr(1),\nwhich historically wasn't implemented correctly on all platforms. But\nquoting tr(1p):\n\n    It was considered that automatically stripping NUL characters from\n    the input was not correct functionality.  However, the removal of -n\n    in a later proposal does not remove the requirement that tr\n    correctly process NUL characters in its input stream.\n\nSo when tr(1) is implemented following the POSIX standard then it is\nexpected to handle the transliteration of NUL just fine.\n\nRefactor the helpers accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 79377bc0fc2..377f08a1428 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -88,15 +88,15 @@ test_decode_color () {\n }\n \n lf_to_nul () {\n-\tperl -pe 'y/\\012/\\000/'\n+\ttr '\\012' '\\000'\n }\n \n nul_to_q () {\n-\tperl -pe 'y/\\000/Q/'\n+\ttr '\\000' 'Q'\n }\n \n q_to_nul () {\n-\tperl -pe 'y/Q/\\000/'\n+\ttr 'Q' '\\000'\n }\n \n q_to_cr () {\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515549","messageId":"20250403-b4-pks-t-perlless-v4-4-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 04/20] t: adapt `test_copy_bytes()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:55Z","receivedAt":"2025-04-03T05:06:04Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_copy_bytes()` helper function copies up to N bytes from stdin\nto stdout. This is implemented using Perl, but it can be trivially\nadapted to instead use dd(1).\n\nRefactor the helper accordingly, which allows a bunch of tests to pass\nwhen Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/test-lib-functions.sh | 12 +-----------\n 1 file changed, 1 insertion(+), 11 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 377f08a1428..c4b4d3a4c7f 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1640,17 +1640,7 @@ test_match_signal () {\n \n # Read up to \"$1\" bytes (or to EOF) from stdin and write them to stdout.\n test_copy_bytes () {\n-\tperl -e '\n-\t\tmy $len = $ARGV[1];\n-\t\twhile ($len > 0) {\n-\t\t\tmy $s;\n-\t\t\tmy $nread = sysread(STDIN, $s, $len);\n-\t\t\tdie \"cannot read: $!\" unless defined($nread);\n-\t\t\tlast unless $nread;\n-\t\t\tprint $s;\n-\t\t\t$len -= $nread;\n-\t\t}\n-\t' - \"$1\"\n+\tdd ibs=1 count=\"$1\" 2>/dev/null\n }\n \n # run \"$@\" inside a non-git directory\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515550","messageId":"20250403-b4-pks-t-perlless-v4-5-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 05/20] t: adapt `test_readlink()` to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:56Z","receivedAt":"2025-04-03T05:06:06Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `test_readlink()` helper function reads a symbolic link and returns\nthe path it is pointing to. It is thus equivalent to the readlink(1)\nutility, which isn't available on all supported platforms. As such, it\nis implemented using Perl so that we can use it even on platforms where\nthe shell utility isn't available.\n\nWhile using readlink(1) is not an option, what we can do is to implement\nthe logic ourselves in our test-tool. Do so, which allows a bunch of\ntests to pass when Perl is not available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-path-utils.c | 13 +++++++++++++\n t/test-lib-functions.sh    |  2 +-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 72ac8d1b1b0..54d9ba98c0e 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc >= 2 && !strcmp(argv[1], \"readlink\")) {\n+\t\tstruct strbuf target = STRBUF_INIT;\n+\t\twhile (argc > 2) {\n+\t\t\tif (strbuf_readlink(&target, argv[2], 0) < 0)\n+\t\t\t\tdie_errno(\"cannot read link at '%s'\", argv[2]);\n+\t\t\tputs(target.buf);\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t}\n+\t\tstrbuf_release(&target);\n+\t\treturn 0;\n+\t}\n+\n \tif (argc >= 2 && !strcmp(argv[1], \"absolute_path\")) {\n \t\twhile (argc > 2) {\n \t\t\tputs(absolute_path(argv[2]));\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex c4b4d3a4c7f..bff8c4d1b41 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1979,7 +1979,7 @@ test_remote_https_urls() {\n # Print the destination of symlink(s) provided as arguments. Basically\n # the same as the readlink command, but it's not available everywhere.\n test_readlink () {\n-\tperl -le 'print readlink($_) for @ARGV' \"$@\"\n+\ttest-tool path-utils readlink \"$@\"\n }\n \n # Set mtime to a fixed \"magic\" timestamp in mid February 2009, before we\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515554","messageId":"20250403-b4-pks-t-perlless-v4-6-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 06/20] t: introduce PERL_TEST_HELPERS prerequisite","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:57Z","receivedAt":"2025-04-03T05:06:08Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"In the early days of Git, Perl was used quite prominently throughout the\nproject. This has changed significantly as almost all of the executables\nwe ship nowadays have eventually been rewritten in C. Only a handful of\nsubsystems remain that require Perl:\n\n  - gitweb, a read-only web interface.\n\n  - A couple of scripts that allow importing repositories from GNU Arch,\n    CVS and Subversion.\n\n  - git-send-email(1), which can be used to send mails.\n\n  - git-request-pull(1), which is used to request somebody to pull from\n    a URL by sending an email.\n\n  - git-filter-branch(1), which uses Perl with the `--state-branch`\n    option. This command is typically recommended against nowadays in\n    favor of git-filter-repo(1).\n\n  - Our Perl bindings for Git.\n\n  - The netrc Git credential helper.\n\nNone of these subsystems can really be considered to be part of the\n\"core\" of Git, and an installation without them is fully functional.\nIt is more likely than not that an end user wouldn't even notice that\nany features are missing if those tools weren't installed. But while\nPerl nowadays very much is an optional dependency of Git, there is a\nsignificant limitation when Perl isn't available: developers cannot run\nour test suite.\n\nPreceding commits have started to lift this restriction by removing the\nstrict dependency on Perl in many central parts of the test library. But\nthere are still many tests that rely on small Perl helpers to do various\ndifferent things.\n\nIntroduce a new PERL_TEST_HELPERS prerequisite that guards all tests\nthat require Perl. This prerequisite is explicitly different than the\npreexisting PERL prerequisite:\n\n  - PERL records whether or not features depending on the Perl\n    interpreter are built.\n\n  - PERL_TEST_HELPERS records whether or not a Perl interpreter is\n    available for our tests.\n\nBy having these two separate prerequisites we can thus distinguish\nbetween tests that inherently depend on Perl because the underlying\nfeature does, and those tests that depend on Perl because the test\nitself is using Perl.\n\nAdapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        |  6 ++++++\n t/t0021-conversion.sh                     |  4 ++--\n t/t0210-trace2-normal.sh                  |  6 ++++++\n t/t0211-trace2-perf.sh                    |  6 ++++++\n t/t0610-reftable-basics.sh                |  2 +-\n t/t0613-reftable-write-options.sh         |  2 +-\n t/t1006-cat-file.sh                       |  2 +-\n t/t1007-hash-object.sh                    |  6 +++---\n t/t1010-mktree.sh                         |  4 ++--\n t/t1450-fsck.sh                           |  6 +++---\n t/t3300-funny-names.sh                    |  6 +++---\n t/t4013-diff-various.sh                   |  6 ++++++\n t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------\n t/t4020-diff-external.sh                  |  4 ++--\n t/t4029-diff-trailing-space.sh            |  2 +-\n t/t4030-diff-textconv.sh                  |  6 ++++++\n t/t4031-diff-rewrite-binary.sh            |  2 +-\n t/t4058-diff-duplicates.sh                |  6 ++++++\n t/t4103-apply-binary.sh                   |  6 ++++++\n t/t4116-apply-reverse.sh                  |  6 ++++++\n t/t4150-am.sh                             |  2 +-\n t/t4200-rerere.sh                         |  6 ++++++\n t/t4205-log-pretty-formats.sh             |  6 +++---\n t/t4216-log-bloom.sh                      |  8 ++++----\n t/t5004-archive-corner-cases.sh           |  6 ++++++\n t/t5300-pack-object.sh                    |  6 ++++++\n t/t5303-pack-corruption-resilience.sh     |  4 ++--\n t/t5310-pack-bitmaps.sh                   |  2 +-\n t/t5316-pack-delta-depth.sh               |  8 ++++----\n t/t5318-commit-graph.sh                   | 12 ++++++------\n t/t5319-multi-pack-index.sh               | 16 ++++++++--------\n t/t5324-split-commit-graph.sh             |  2 +-\n t/t5326-multi-pack-bitmaps.sh             |  2 +-\n t/t5328-commit-graph-64bit-time.sh        |  2 +-\n t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++\n t/t5400-send-pack.sh                      |  2 +-\n t/t5410-receive-pack-alternates.sh        |  4 ++--\n t/t5503-tagfollow.sh                      |  6 ++++++\n t/t5504-fetch-receive-strict.sh           |  2 +-\n t/t5510-fetch.sh                          |  6 ++++++\n t/t5532-fetch-proxy.sh                    |  6 ++++++\n t/t5534-push-signed.sh                    |  2 +-\n t/t5537-fetch-shallow.sh                  |  2 +-\n t/t5551-http-fetch-smart.sh               |  7 +++++++\n t/t5562-http-backend-content-length.sh    |  6 ++++++\n t/t5601-clone.sh                          |  4 ++--\n t/t5616-partial-clone.sh                  |  6 +++---\n t/t5701-git-serve.sh                      |  2 +-\n t/t5702-protocol-v2.sh                    |  6 +++---\n t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++\n t/t5710-promisor-remote-capability.sh     |  6 ++++++\n t/t6002-rev-list-bisect.sh                |  6 ++++++\n t/t6003-rev-list-topo-order.sh            |  6 ++++++\n t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++\n t/t6013-rev-list-reverse-parents.sh       |  4 ++--\n t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++\n t/t6115-rev-list-du.sh                    |  6 ++++++\n t/t6300-for-each-ref.sh                   |  6 ++++++\n t/t7006-pager.sh                          |  2 +-\n t/t7416-submodule-dash-url.sh             |  6 ++++++\n t/t7508-status.sh                         |  2 +-\n t/t7815-grep-binary.sh                    |  6 ++++++\n t/t8001-annotate.sh                       |  6 ++++++\n t/t8002-blame.sh                          |  6 ++++++\n t/t8006-blame-textconv.sh                 |  6 ++++++\n t/t8011-blame-split-file.sh               |  6 +++---\n t/t8012-blame-colors.sh                   |  6 ++++++\n t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--\n t/t9350-fast-export.sh                    |  2 +-\n t/t9850-shell.sh                          |  2 +-\n t/test-lib.sh                             |  1 +\n 71 files changed, 281 insertions(+), 93 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c9376dffb58..1aaa6bf5ae8 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,6 +5,12 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping ignores tests; Perl not available'\n+\ttest_done\n+fi\n+\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 3f6433d3045..9c3738ebb3f 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success 'required process filter should process multiple packets' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '\n \t)\n '\n \n-test_expect_success 'required process filter with clean error should fail' '\n+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex 4287ed3fbb3..ba4c0442b85 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\ndiff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh\nindex bac90465406..760cf69087f 100755\n--- a/t/t0211-trace2-perf.sh\n+++ b/t/t0211-trace2-perf.sh\n@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping trace2 tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_PERF_BRIEF\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 4618ffc108e..5e0a1fa176d 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success 'basic: can write large commit message' '\n+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \tperl -e \"\ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex e2708e11d5b..fa1e2f9eef8 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success 'small block size fails with large reflog message' '\n+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 398865d6ebe..a574da3df53 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1270,7 +1270,7 @@ extract_batch_output () {\n     ' \"$@\"\n }\n \n-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '\n+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '\n \tgit cat-file --batch-all-objects --batch >actual.raw &&\n \textract_batch_output $orig <actual.raw >actual &&\n \t{\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex a0481139de5..b3cf53ff8c9 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '\n \tgrep \"too-short tree object\" err\n '\n \n-test_expect_success 'malformed mode in tree' '\n+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"9100644 \\0$bin_oid\" >tree-with-malformed-mode &&\n@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '\n \tgrep \"malformed mode in tree entry\" err\n '\n \n-test_expect_success 'empty filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \tprintf \"100644 \\0$bin_oid\" >tree-with-empty-filename &&\n@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '\n \tgrep \"empty filename in tree entry\" err\n '\n \n-test_expect_success 'duplicate filename in tree' '\n+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '\n \thex_oid=$(echo foo | git hash-object --stdin -w) &&\n \tbin_oid=$(echo $hex_oid | hex2oct) &&\n \t{\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex c291a2b33d7..4977998e205 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n \tperl -e \"print reverse <>\" <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n \tperl -e \"print reverse <>\" <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\ndiff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh\nindex 8a456b1142d..01050453762 100755\n--- a/t/t1450-fsck.sh\n+++ b/t/t1450-fsck.sh\n@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '\n \ttest_grep ! \"fatal: empty filename in tree entry\" out\n '\n \n-test_expect_success 'tree entry with type mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \ttest_when_finished \"remove_object \\$commit\" &&\n@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '\n \ttest_grep ! \"dangling blob\" out\n '\n \n-test_expect_success 'tree entry with bogus mode' '\n+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '\n \ttest_when_finished \"remove_object \\$blob\" &&\n \ttest_when_finished \"remove_object \\$tree\" &&\n \tblob=$(echo blob | git hash-object -w --stdin) &&\n@@ -984,7 +984,7 @@ corrupt_index_checksum () {\n \n # Corrupt the checksum on the index and then\n # verify that only fsck notices.\n-test_expect_success 'detect corrupt index file in fsck' '\n+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '\n \tcp .git/index .git/index.backup &&\n \ttest_when_finished \"mv .git/index.backup .git/index\" &&\n \tcorrupt_index_checksum &&\ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex f5bf16abcd8..502b1572059 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'ls-files -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-index -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success 'diff-tree -z does not quote funny filename' '\n+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 3855d68dbc0..782d97fb7df 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-diff.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff various tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \tGIT_AUTHOR_DATE=\"2006-06-26 00:00:00 +0000\" &&\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 884f83fb8a4..2782b1fc183 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF\n ---\n EOF\n \n-test_expect_success 'no threading' '\n+test_expect_success PERL_TEST_HELPERS 'no threading' '\n \tgit checkout side &&\n \tcheck_threading expect.no-threading main\n '\n@@ -466,11 +466,11 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread' '\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success '--thread overrides format.thread=deep' '\n+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n@@ -490,7 +490,7 @@ In-Reply-To: <1>\n References: <1>\n EOF\n \n-test_expect_success 'thread in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '\n \tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n \t\t--thread main\n '\n@@ -512,7 +512,7 @@ In-Reply-To: <0>\n References: <0>\n EOF\n \n-test_expect_success 'thread cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '\n \tcheck_threading expect.cover-letter --cover-letter --thread main\n '\n \n@@ -538,12 +538,12 @@ References: <1>\n \t<0>\n EOF\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread main\n '\n \n-test_expect_success 'thread explicit shallow' '\n+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '\n \tcheck_threading expect.cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=shallow main\n '\n@@ -562,7 +562,7 @@ References: <0>\n \t<1>\n EOF\n \n-test_expect_success 'thread deep' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep' '\n \tcheck_threading expect.deep --thread=deep main\n '\n \n@@ -584,7 +584,7 @@ References: <1>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '\n \tcheck_threading expect.deep-irt  --thread=deep \\\n \t\t--in-reply-to=\"<test.message>\" main\n '\n@@ -609,7 +609,7 @@ References: <0>\n \t<2>\n EOF\n \n-test_expect_success 'thread deep cover-letter' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '\n \tcheck_threading expect.deep-cl --cover-letter --thread=deep main\n '\n \n@@ -638,27 +638,27 @@ References: <1>\n \t<3>\n EOF\n \n-test_expect_success 'thread deep cover-letter in-reply-to' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '\n \tcheck_threading expect.deep-cl-irt --cover-letter \\\n \t\t--in-reply-to=\"<test.message>\" --thread=deep main\n '\n \n-test_expect_success 'thread via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread via config' '\n \ttest_config format.thread true &&\n \tcheck_threading expect.thread main\n '\n \n-test_expect_success 'thread deep via config' '\n+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.deep main\n '\n \n-test_expect_success 'thread config + override' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + override' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.thread --thread main\n '\n \n-test_expect_success 'thread config + --no-thread' '\n+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '\n \ttest_config format.thread deep &&\n \tcheck_threading expect.no-threading --no-thread main\n '\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex f1efe482a59..189294de7ef 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet\n \n echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n \n-test_expect_success 'force diff with \"diff\"' '\n+test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success 'diff --cached' '\n+test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex 32b6e9a4e76..a92a42990b1 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success \"$test_description\" '\n+test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex daebf9796f5..c7d8eb12453 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex c4394a27b56..cbe50b15772 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success 'rewrite diff respects textconv' '\n+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n \tgrep \"dissimilarity index\" diff &&\n \tgrep \"^-61\" diff &&\ndiff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh\nindex 2fce4a98977..16266dff2af 100755\n--- a/t/t4058-diff-duplicates.sh\n+++ b/t/t4058-diff-duplicates.sh\n@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping diff duplicates tests; Perl not available'\n+\ttest_done\n+fi\n+\n # make_tree_entry <mode> <mode> <sha1>\n #\n # We have to rely on perl here because not all printfs understand\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex d370ecfe0d9..59d38793ae6 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply-binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 0784ba033a4..6f414ad27f5 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,6 +10,12 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping apply reverse tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 5e2b6c80eae..4794510d70d 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success 'am works with multi-line in-body headers' '\n+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex b0a3e849841..50fe8b0fd05 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rerere tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex f81e42a84d5..8f2ba98963f 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only \"key: value\" trail\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:unfold) unfolds trailers' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '\n \tgit log --no-walk --pretty=\"%(trailers:unfold)\" >actual &&\n \t{\n \t\tunfold <trailers &&\n@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success ':only and :unfold work together' '\n+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '\n \tgit log --no-walk --pretty=\"%(trailers:only,unfold)\" >actual &&\n \tgit log --no-walk --pretty=\"%(trailers:unfold,only)\" >reverse &&\n \ttest_cmp actual reverse &&\n@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'\n \ttest_cmp expect actual\n '\n \n-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '\n+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '\n \tgit log --no-walk --pretty=\"format:%(trailers:key=Signed-Off-by,unfold)\" >actual &&\n \tunfold <trailers | grep Signed-off-by >expect &&\n \ttest_cmp expect actual\ndiff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh\nindex 3f163dc3969..8910d53cac1 100755\n--- a/t/t4216-log-bloom.sh\n+++ b/t/t4216-log-bloom.sh\n@@ -738,20 +738,20 @@ check_corrupt_graph () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'Bloom reader notices too-small data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '\n \tcheck_corrupt_graph BDAT clear 00000000 &&\n \techo \"warning: ignoring too-small changed-path chunk\" \\\n \t\t\"(4 < 12) in commit-graph file\" >expect.err &&\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '\n \tcheck_corrupt_graph BIDX 12 FFFFFFFF &&\n \t# use grep to avoid depending on exact chunk size\n \tgrep \"warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph\" err\n '\n \n-test_expect_success 'Bloom reader notices too-small index chunk' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '\n \t# replace the index with a single entry, making most\n \t# lookups out-of-bounds\n \tcheck_corrupt_graph BIDX clear 00000000 &&\n@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'Bloom reader notices out-of-order index offsets' '\n+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '\n \t# we do not know any real offsets, but we can pick\n \t# something plausible; we should not get to the point of\n \t# actually reading from the bogus offsets anyway.\ndiff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh\nindex 50344e17ca1..51749951916 100755\n--- a/t/t5004-archive-corner-cases.sh\n+++ b/t/t5004-archive-corner-cases.sh\n@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping archive corner cases tests; Perl not available'\n+\ttest_done\n+fi\n+\n # the 10knuls.tar file is used to test for an empty git generated tar\n # without having to invoke tar because an otherwise valid empty GNU tar\n # will be considered broken by {Open,Net}BSD tar\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 5ac8d39094b..143856c29f1 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,6 +7,12 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pack-object tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n \tperl -e \"print \\\"a\\\" x 4096;\" >a &&\ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex de58ca654a1..ac5e370e1e4 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first object' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n@@ -156,7 +156,7 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success 'create corruption in data of first delta' '\n+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 621bbbdd26e..81987296235 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex 32cf4227451..cd947b5a5ef 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -87,7 +87,7 @@ max_chain() {\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success 'packing produces a long delta' '\n+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth limits depth' '\n+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success '--depth=0 disables deltas' '\n+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'negative depth disables deltas' '\n+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\ndiff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh\nindex f68f64cd85e..0b3404f58fe 100755\n--- a/t/t5318-commit-graph.sh\n+++ b/t/t5318-commit-graph.sh\n@@ -837,7 +837,7 @@ check_corrupt_chunk () {\n \ttest_cmp expect.out out\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \t# make it big enough that the graph file is plausible,\n \t# otherwise we hit an earlier check\n \tcheck_corrupt_chunk OIDF clear $(printf \"000000%02x\" $(test_seq 250)) &&\n@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices fanout/lookup table mismatch' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '\n \tcheck_corrupt_chunk OIDF 1020 \"FFFFFFFF\" &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph OID lookup chunk is the wrong size\n@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# Rather than try to corrupt a specific hash, we will just\n \t# wreck them all. But we cannot just set them all to 0xFFFFFFFF or\n \t# similar, as they are used for hi/lo starts in a binary search (so if\n@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small commit data chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '\n \tcheck_corrupt_chunk CDAT clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph commit data chunk is wrong size\n@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds extra edge' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '\n \tcheck_corrupt_chunk EDGE clear &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph extra-edges pointer out of bounds\n@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small generations chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '\n \tcheck_corrupt_chunk GDA2 clear 00000000 &&\n \tcat >expect.err <<-\\EOF &&\n \terror: commit-graph generations chunk is wrong size\ndiff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh\nindex 0f215ad2e88..bd75dea9501 100755\n--- a/t/t5319-multi-pack-index.sh\n+++ b/t/t5319-multi-pack-index.sh\n@@ -1120,7 +1120,7 @@ corrupt_chunk () {\n \tcorrupt_chunk_file $midx \"$@\"\n }\n \n-test_expect_success 'reader notices too-small oid fanout chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '\n \tcorrupt_chunk OIDF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small oid lookup chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '\n \tcorrupt_chunk OIDL clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader notices too-small pack names chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '\n \t# There is no NUL to terminate the name here, so the\n \t# chunk is too short.\n \tcorrupt_chunk PNAM clear 70656666 &&\n@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader handles unaligned chunks' '\n+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '\n \t# A 9-byte PNAM means all of the subsequent chunks\n \t# will no longer be 4-byte aligned, but it is still\n \t# a valid one-pack chunk on its own (it is \"foo.pack\\0\").\n@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices too-small object offset chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '\n \tcorrupt_chunk OOFF clear 00000000 &&\n \ttest_must_fail git log 2>err &&\n \tcat >expect <<-\\EOF &&\n@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'reader bounds-checks large offset table' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '\n \t# re-use the objects64 dir here to cheaply get access to a midx\n \t# with large offsets.\n \tgit init repo &&\n@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '\n \t)\n '\n \n-test_expect_success 'reader notices too-small revindex chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '\n \t# We only get a revindex with bitmaps (and likewise only\n \t# load it when they are asked for).\n \ttest_config repack.writeBitmaps true &&\n@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '\n \ttest_cmp expect.err err\n '\n \n-test_expect_success 'reader notices out-of-bounds fanout' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '\n \t# This is similar to the out-of-bounds fanout test in t5318. The values\n \t# in adjacent entries should be large but not identical (they\n \t# are used as hi/lo starts for a binary search, which would then abort\ndiff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh\nindex a32be3867df..49a057cc2eb 100755\n--- a/t/t5324-split-commit-graph.sh\n+++ b/t/t5324-split-commit-graph.sh\n@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '\n \t)\n '\n \n-test_expect_success 'reader bounds-checks base-graph chunk' '\n+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '\n \tgit clone --no-hardlinks . corrupt-base-chunk &&\n \t(\n \t\tcd corrupt-base-chunk &&\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex d27557b9b04..627f8b4efdc 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success 'pack.preferBitmapTips' '\n+\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\ndiff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh\nindex a766a3e3f84..d8891e6a922 100755\n--- a/t/t5328-commit-graph-64bit-time.sh\n+++ b/t/t5328-commit-graph-64bit-time.sh\n@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '\n \tgit -C repo-uint32-max commit-graph verify\n '\n \n-test_expect_success 'reader notices out-of-bounds generation overflow' '\n+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '\n \tgraph=.git/objects/info/commit-graph &&\n \ttest_when_finished \"rm -rf $graph\" &&\n \tgit commit-graph write --reachable &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 3905cb6e4f1..1059ff45fe4 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\ndiff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh\nindex 3f81f16e133..571e8f1bc59 100755\n--- a/t/t5400-send-pack.sh\n+++ b/t/t5400-send-pack.sh\n@@ -268,7 +268,7 @@ extract_ref_advertisement () {\n \t'\n }\n \n-test_expect_success 'receive-pack de-dupes .have lines' '\n+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '\n \tgit init shared &&\n \tgit -C shared commit --allow-empty -m both &&\n \tgit clone -s shared fork &&\ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 0b28e4e452f..6a009fdcd71 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -20,7 +20,7 @@ extract_haves () {\n \tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n }\n \n-test_expect_success 'with core.alternateRefsCommand' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success 'with core.alternateRefsPrefixes' '\n+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nindex 845ca43ea0a..febe4410417 100755\n--- a/t/t5503-tagfollow.sh\n+++ b/t/t5503-tagfollow.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping tagfollow tests; Perl not available'\n+\ttest_done\n+fi\n+\n # End state of the repository:\n #\n #         T - tag1          S - tag2\ndiff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh\nindex 58074506c59..438250c75ed 100755\n--- a/t/t5504-fetch-receive-strict.sh\n+++ b/t/t5504-fetch-receive-strict.sh\n@@ -359,7 +359,7 @@ test_expect_success \\\n \tgrep \"Cannot demote unterminatedheader\" act\n '\n \n-test_expect_success 'badFilemode is not a strict error' '\n+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '\n \tgit init --bare badmode.git &&\n \ttree=$(\n \t\tcd badmode.git &&\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 5f350facf5e..432a2264e6f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -8,6 +8,12 @@ test_description='Per branch config variables affects \"git fetch\".\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-bundle.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch tests; Perl not available'\n+\ttest_done\n+fi\n+\n D=$(pwd)\n \n test_expect_success setup '\ndiff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh\nindex 37558226290..95d0f33b295 100755\n--- a/t/t5532-fetch-proxy.sh\n+++ b/t/t5532-fetch-proxy.sh\n@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping fetch proxy tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup remote repo' '\n \tgit init remote &&\n \t(cd remote &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex c91a62b77af..342d0423c92 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 37f7547a4ca..77d20d19110 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\ndiff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh\nindex 761fdfcfe6c..b0d4ea78015 100755\n--- a/t/t5551-http-fetch-smart.sh\n+++ b/t/t5551-http-fetch-smart.sh\n@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n+\n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http fetch smart tests; Perl not available'\n+\ttest_done\n+fi\n+\n test \"$HTTP_PROTO\" = \"HTTP/2\" && enable_http2\n start_httpd\n \ndiff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh\nindex f3b158274c4..b6ee06f5c8f 100755\n--- a/t/t5562-http-backend-content-length.sh\n+++ b/t/t5562-http-backend-content-length.sh\n@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping http backend content tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_lazy_prereq GZIP 'gzip --version'\n \n verify_http_result() {\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d0c18660e33..d743d986c40 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '\n \tgit -C replay.git index-pack -v --stdin <tmp.pack\n '\n \n-test_expect_success 'clone on case-insensitive fs' '\n+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '\n \tgit init icasefs &&\n \t(\n \t\tcd icasefs &&\n@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '\n \t)\n '\n \n-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '\n+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '\n \tgrep X icasefs/warning &&\n \tgrep x icasefs/warning &&\n \ttest_grep \"the following paths have collided\" icasefs/warning\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 46504519643..bc7e0fec8dc 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -751,7 +751,7 @@ replace_packfile () {\n \t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n }\n \n-test_expect_success 'upon cloning, check that all refs point to objects' '\n+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of\n \t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n '\n \n-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '\n+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 678a346ed06..200bf06ecb3 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'ignore very large set of prefixes' '\n+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex d3df81e7852..ad5e772cd72 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success 'when server sends \"ready\", expect DELIM' '\n+test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends \"ready\", expect DELIM' '\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n \tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n \ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex 191097171bc..f59d47aa6c6 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n+\ttest_done\n+fi\n+\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\ndiff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh\nindex d2cc69a17e4..9a420cf5605 100755\n--- a/t/t5710-promisor-remote-capability.sh\n+++ b/t/t5710-promisor-remote-capability.sh\n@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping promisor remote capabilities tests; Perl not available'\n+\ttest_done\n+fi\n+\n GIT_TEST_MULTI_PACK_INDEX=0\n GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0\n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex daa009c9a1b..5e1482aff78 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list bisect tests; Perl not available'\n+\ttest_done\n+fi\n+\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 0d7055d46d4..02dd4127aff 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list topo-order tests; Perl not available'\n+\ttest_done\n+fi\n+\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex bad02cf5b83..6131c361094 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 39793cbbd66..8074185742c 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success '--reverse --parents --full-history combines correctly' '\n+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n \tgit rev-list --parents --full-history main -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success '--boundary does too' '\n+test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n \tgit rev-list --boundary --parents --full-history main ^root -- foo |\n \t\tperl -e \"print reverse <>\" > expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 22dfd6d978e..eb98b3919c8 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list unexpected objects tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup well-formed objects' '\n \tblob=\"$(printf \"foo\" | git hash-object -w --stdin)\" &&\n \ttree=\"$(printf \"100644 blob $blob\\tfoo\" | git mktree)\" &&\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 3385fe9f130..6a74be576a2 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping rev-list disk usage tests; Perl not available'\n+\ttest_done\n+fi\n+\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex a5c77943854..732a4d3171e 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping for-each-ref tests; Perl not available'\n+\ttest_done\n+fi\n+\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 932c26cb45b..49aae183829 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success 'setup large log output' '\n+test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n \tperl -e \"\n \t\tprint \\\"this is a long commit message\\\" x 50000\n \t\" >commit-msg &&\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 0c605fd271a..14069600a2f 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping submodule dash URL tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex b2070d4e39f..14c41b2cb7c 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success 'status -z implies porcelain' '\n+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n \tgit status --porcelain |\n \tperl -pe \"s/\\012/\\000/g\" >expect &&\n \tgit status -z >output &&\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex 90ebb64f46e..b2730d200c8 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,6 +4,12 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping grep binary tests; Perl not available'\n+\ttest_done\n+fi\n+\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\ndiff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh\nindex d7167f55397..609845aeb1e 100755\n--- a/t/t8001-annotate.sh\n+++ b/t/t8001-annotate.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping annotate tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git annotate'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex e98993276a6..b40199df231 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 07a287ffd3e..5cb16872081 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,6 +4,12 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame textconv tests; Perl not available'\n+\ttest_done\n+fi\n+\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\ndiff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh\nindex c66494f5ba7..388057245c8 100755\n--- a/t/t8011-blame-split-file.sh\n+++ b/t/t8011-blame-split-file.sh\n@@ -81,7 +81,7 @@ do\n \t\tgit blame --root -C --$output combined >output\n \t'\n \n-\ttest_expect_success \"$output output finds correct commits\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output finds correct commits\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t5 base\n \t\t1 modified\n@@ -93,7 +93,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct filenames\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct filenames\" '\n \t\tgenerate_expect >expect <<-\\EOF &&\n \t\t11 one\n \t\t11 two\n@@ -102,7 +102,7 @@ do\n \t\ttest_cmp expect actual\n \t'\n \n-\ttest_expect_success \"$output output shows correct previous pointer\" '\n+\ttest_expect_success PERL_TEST_HELPERS \"$output output shows correct previous pointer\" '\n \t\tgenerate_expect >expect <<-EOF &&\n \t\t5 NONE\n \t\t1 $(git rev-parse modified^) one\ndiff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh\nindex c3a5f6d01ff..3d77352650f 100755\n--- a/t/t8012-blame-colors.sh\n+++ b/t/t8012-blame-colors.sh\n@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n+if ! test_have_prereq PERL_TEST_HELPERS\n+then\n+\tskip_all='skipping blame colors tests; Perl not available'\n+\ttest_done\n+fi\n+\n PROG='git blame -c'\n . \"$TEST_DIRECTORY\"/annotate-tests.sh\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex 067b15bad25..a9d38be997c 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success '(supposedly) non-conflicting change from SVN' '\n+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success 'change file but in unrelated area' \"\n+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n \tperl -i.bak -p -e 's/^4\\$/4444/' file &&\ndiff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh\nindex 40427883ec6..0781a8d6ace 100755\n--- a/t/t9350-fast-export.sh\n+++ b/t/t9350-fast-export.sh\n@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '\n \t(cd result && git show main:foo)\n '\n \n-test_expect_success 'fast-export quotes pathnames' '\n+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '\n \tgit init crazy-paths &&\n \ttest_config -C crazy-paths core.protectNTFS false &&\n \t(cd crazy-paths &&\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex 36566ace21b..f619b60f226 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'shell complains of overlong commands' '\n+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n \tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex a62699d6c79..59162a3c834 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1706,6 +1706,7 @@ test -n \"$USE_LIBPCRE2\" && test_set_prereq LIBPCRE2\n test -z \"$NO_GETTEXT\" && test_set_prereq GETTEXT\n test -n \"$SANITIZE_LEAK\" && test_set_prereq SANITIZE_LEAK\n test -n \"$GIT_VALGRIND_ENABLED\" && test_set_prereq VALGRIND\n+test -n \"$PERL_PATH\" && test_set_prereq PERL_TEST_HELPERS\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515551","messageId":"20250403-b4-pks-t-perlless-v4-7-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 07/20] t: adapt existing PERL prerequisites","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:58Z","receivedAt":"2025-04-03T05:06:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A couple of our tests depend on the PERL prerequisite even though it\nisn't needed. These tests fall into one of the following classes:\n\n  - The underlying logic used to be implemented in Perl but isn't\n    anymore. Here we can simply drop the dependency altogether.\n\n  - The test logic used to depend on Perl but doesn't anymore. Again, we\n    can simply drop the dependency.\n\n  - The test logic still relies on a Perl interpreter. These tests\n    should use the newly introduced PERL_TEST_HELPERS prerequisite.\n\nAdapt test cases accordingly.\n\nNote that in t1006 we have to introduce another new prerequisite\ndepending on whether or not the IPC::Open2 module is available. Funny\nenough, when starting to use `test_lazy_prereq` to do so we also get a\nconflict of variables with the \"script\" variable that contains the Perl\nlogic because `test_run_lazy_prereq_` also sets that variable. We thus\nrename the variable in t1006 to \"perl_script\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh                 | 10 +++++-----\n t/t0090-cache-tree.sh                 |  4 ++--\n t/t1006-cat-file.sh                   | 14 +++++++++-----\n t/t7501-commit-basic-functionality.sh |  6 +++---\n 4 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 9c3738ebb3f..4a892a91780 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'\n \t)\n '\n \n-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n+test_expect_success 'invalid process filter must fail (and not hang!)' '\n \ttest_config_global filter.protocol.process cat &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n@@ -1111,19 +1111,19 @@ do\n \tbranch) opt='-f HEAD' ;;\n \tesac\n \n-\ttest_expect_success PERL,TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout shows progress by default on tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress test_terminal git checkout $opt\n \t'\n \n-\ttest_expect_success PERL \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n+\ttest_expect_success \"delayed checkout omits progress on non-tty ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! git checkout $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout omits progress with --quiet ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --quiet $opt\n \t'\n \n-\ttest_expect_success PERL,TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n+\ttest_expect_success TTY \"delayed checkout honors --[no]-progress ($mode checkout)\" '\n \t\ttest_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&\n \t\ttest_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt\n \t'\ndiff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh\nindex ab80c9ef135..d9015882946 100755\n--- a/t/t0090-cache-tree.sh\n+++ b/t/t0090-cache-tree.sh\n@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '\n \ttest_cache_tree\n '\n \n-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '\n+test_expect_success 'commit --interactive gives cache-tree on partial commit' '\n \ttest_when_finished \"git reset --hard\" &&\n \tcat <<-\\EOT >foo.c &&\n \tint foo()\n@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi\n \ttest_cache_tree expected.status\n '\n \n-test_expect_success PERL 'commit -p with shrinking cache-tree' '\n+test_expect_success 'commit -p with shrinking cache-tree' '\n \tmkdir -p deep/very-long-subdir &&\n \techo content >deep/very-long-subdir/file &&\n \tgit add deep &&\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex a574da3df53..0a22b0a7b8e 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '\n \tgrep \"^fatal:.*flush is only for --buffer mode.*\" err\n '\n \n-script='\n+perl_script='\n use warnings;\n use strict;\n use IPC::Open2;\n@@ -1345,12 +1345,16 @@ $? == 0 or die \"\\$?=$?\";\n \n expect=\"$hello_oid blob $hello_size\"\n \n-test_expect_success PERL '--batch-check is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-check $hello_oid \"$expect\"\n+test_lazy_prereq PERL_IPC_OPEN2 '\n+\tperl -MIPC::Open2 -e \"exit 0\"\n '\n \n-test_expect_success PERL '--batch-command info is unbuffered by default' '\n-\tperl -e \"$script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-check $hello_oid \"$expect\"\n+'\n+\n+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '\n+\tperl -e \"$perl_script\" -- --batch-command $hello_oid \"$expect\" \"info \"\n '\n \n test_done\ndiff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh\nindex cc12f99f115..a37509f0043 100755\n--- a/t/t7501-commit-basic-functionality.sh\n+++ b/t/t7501-commit-basic-functionality.sh\n@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '\n \ttest_must_fail git commit -m foo -a file\n '\n \n-test_expect_success PERL 'can use paths with --interactive' '\n+test_expect_success 'can use paths with --interactive' '\n \techo bong-o-bong >file &&\n \t# 2: update, 1:st path, that is all, 7: quit\n \ttest_write_lines 2 1 \"\" 7 |\n@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '\n \tgrep Rubber.Duck output\n '\n \n-test_expect_success PERL 'interactive add' '\n+test_expect_success 'interactive add' '\n \techo 7 | test_must_fail git commit --interactive >out &&\n \tgrep \"What now\" out\n '\n \n-test_expect_success PERL \"commit --interactive doesn't change index if editor aborts\" '\n+test_expect_success \"commit --interactive doesn't change index if editor aborts\" '\n \techo zoo >file &&\n \ttest_must_fail git diff --exit-code >diff1 &&\n \ttest_write_lines u \"*\" q |\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515552","messageId":"20250403-b4-pks-t-perlless-v4-8-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 08/20] meson: stop requiring Perl when tests are enabled","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:05:59Z","receivedAt":"2025-04-03T05:06:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Perl interpreter used to be a strict dependency for running our test\nsuite. This requirement is explicit in the Meson build system, where we\nrequire Perl to be present unless tests have been disabled.\n\nWith the preceding commits we have loosened this restriction so that it\nis now possible to run tests when Perl is unavailable. Loosen the above\nrequirement accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n meson.build | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/meson.build b/meson.build\nindex efe2871c9db..d6e27b236fa 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -772,7 +772,7 @@ endif\n # features. It is optional if you want to neither execute tests nor use any of\n # these optional features.\n perl_required = get_option('perl')\n-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')\n   perl_required = true\n endif\n \n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515553","messageId":"20250403-b4-pks-t-perlless-v4-9-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 09/20] Makefile: stop requiring Perl when running tests","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:00Z","receivedAt":"2025-04-03T05:06:10Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The Makefile for our tests has a couple of targets that depend on Perl.\nAdapt those targets to only run conditionally in case Perl is available\non the system so that it becomes possible to run the test suite without\nPerl.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/Makefile | 16 +++++++++++++---\n 1 file changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/t/Makefile b/t/Makefile\nindex 2994eb5fa9a..791e0a09789 100644\n--- a/t/Makefile\n+++ b/t/Makefile\n@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT\n \n all:: $(DEFAULT_TEST_TARGET)\n \n-test: pre-clean check-chainlint check-meson $(TEST_LINT)\n+test: pre-clean check-meson $(TEST_LINT)\n \t$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup\n \n+ifneq ($(PERL_PATH),)\n+test: check-chainlint\n+prove: check-chainlint\n+endif\n+\n failed:\n \t@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \\\n \t\tgrep -l '^failed [1-9]' *.counts | \\\n \t\tsed -n 's/\\.counts$$/.sh/p') && \\\n \ttest -z \"$$failed\" || $(MAKE) $$failed\n \n-prove: pre-clean check-chainlint $(TEST_LINT)\n+prove: pre-clean $(TEST_LINT)\n \t@echo \"*** prove (shell & unit tests) ***\"\n \t@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)\n \t$(MAKE) clean-except-prove-cache\n@@ -132,8 +137,13 @@ check-meson:\n \t\tfi; \\\n \tdone\n \n-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \\\n+test-lint: test-lint-duplicates test-lint-executable \\\n \ttest-lint-filenames\n+ifneq ($(PERL_PATH),)\n+test-lint: test-lint-shell-syntax\n+else\n+GIT_TEST_CHAIN_LINT = 0\n+endif\n ifneq ($(GIT_TEST_CHAIN_LINT),0)\n test-lint: test-chainlint\n endif\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515555","messageId":"20250403-b4-pks-t-perlless-v4-10-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 10/20] t: refactor tests depending on Perl transliteration operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:01Z","receivedAt":"2025-04-03T05:06:10Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform character\ntransliteration via the \"y/\" or \"tr/\" operator. These usecases can be\ntrivially replaced with tr(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/helper/test-sha1.sh    |  4 ++--\n t/lib-diff.sh            |  4 ++--\n t/t3300-funny-names.sh   | 12 ++++++------\n t/t4020-diff-external.sh |  6 +++---\n t/t4103-apply-binary.sh  | 12 +++---------\n t/t4116-apply-reverse.sh | 10 ++--------\n t/t4200-rerere.sh        |  2 +-\n 7 files changed, 19 insertions(+), 31 deletions(-)\n\ndiff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh\nindex bf387d3db14..f03b784ddc2 100755\n--- a/t/helper/test-sha1.sh\n+++ b/t/helper/test-sha1.sh\n@@ -15,7 +15,7 @@ do\n \t\t\t{\n \t\t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\t\ttr \"\\000\" \"g\"\n \t\t\t} | ./t/helper/test-tool $sha1 $cnt\n \t\t)\n \t\tif test \"$expect\" = \"$actual\"\n@@ -61,7 +61,7 @@ do\n \t\t{\n \t\t\ttest -z \"$pfx\" || echo \"$pfx\"\n \t\t\tdd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |\n-\t\t\tperl -pe 'y/\\000/g/'\n+\t\t\ttr \"\\000\" \"g\"\n \t\t} | sha1sum |\n \t\tsed -e 's/ .*//'\n \t)\ndiff --git a/t/lib-diff.sh b/t/lib-diff.sh\nindex c4606bd4b7f..12b3c8fcc6a 100644\n--- a/t/lib-diff.sh\n+++ b/t/lib-diff.sh\n@@ -21,8 +21,8 @@ compare_diff_raw_z () {\n     # Also we do not check SHA1 hash generation in this test, which\n     # is a job for t0000-basic.sh\n \n-    perl -pe 'y/\\000/\\012/' <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n-    perl -pe 'y/\\000/\\012/' <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n+    tr \"\\000\" \"\\012\" <\"$1\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-1\n+    tr \"\\000\" \"\\012\" <\"$2\" | sed -e \"$sanitize_diff_raw_z\" >.tmp-2\n     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2\n }\n \ndiff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh\nindex 502b1572059..dd0586b0073 100755\n--- a/t/t3300-funny-names.sh\n+++ b/t/t3300-funny-names.sh\n@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '\n+test_expect_success 'ls-files -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tjust space\n \tno-funny\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit ls-files -z >ls-files.z &&\n-\tperl -pe \"y/\\000/\\012/\" <ls-files.z >current &&\n+\ttr \"\\000\" \"\\012\" <ls-files.z >current &&\n \ttest_cmp expected current\n '\n \n@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '\n+test_expect_success 'diff-index -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-index -z --name-status $t0 >diff-index.z &&\n-\tperl -pe \"y/\\000/\\012/\" <diff-index.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-index.z >current &&\n \ttest_cmp expected current\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '\n+test_expect_success 'diff-tree -z does not quote funny filename' '\n \tcat >expected <<-\\EOF &&\n \tA\n \ttabs\t,\" (dq) and spaces\n \tEOF\n \tgit diff-tree -z --name-status $t0 $t1 >diff-tree.z &&\n-\tperl -pe y/\\\\000/\\\\012/ <diff-tree.z >current &&\n+\ttr \"\\000\" \"\\012\" <diff-tree.z >current &&\n \ttest_cmp expected current\n '\n \ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex 189294de7ef..c8a23d51483 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet\n check_external_diff   1 empty  empty 1 on  --quiet\n check_external_diff 128 empty  error 2 on  --quiet\n \n-echo NULZbetweenZwords | perl -pe 'y/Z/\\000/' > file\n+echo NULZbetweenZwords | tr \"Z\" \"\\000\" > file\n \n-test_expect_success PERL_TEST_HELPERS 'force diff with \"diff\"' '\n+test_expect_success 'force diff with \"diff\"' '\n \tafter=$(git hash-object file) &&\n \tafter=$(git rev-parse --short $after) &&\n \techo >.gitattributes \"file diff\" &&\n@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '\n \ttest $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'diff --cached' '\n+test_expect_success 'diff --cached' '\n \ttest_config core.autocrlf true &&\n \tgit add file &&\n \tgit update-index --assume-unchanged file &&\ndiff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh\nindex 59d38793ae6..8e302a5a57e 100755\n--- a/t/t4103-apply-binary.sh\n+++ b/t/t4103-apply-binary.sh\n@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply-binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >file1 <<-\\EOF &&\n \tA quick brown fox jumps over the lazy dog.\n@@ -32,10 +26,10 @@ test_expect_success 'setup' '\n \tgit commit -m \"Initial Version\" 2>/dev/null &&\n \n \tgit checkout -b binary &&\n-\tperl -pe \"y/x/\\000/\" <file1 >file3 &&\n+\ttr \"x\" \"\\000\" <file1 >file3 &&\n \tcat file3 >file4 &&\n \tgit add file2 &&\n-\tperl -pe \"y/\\000/v/\" <file3 >file1 &&\n+\ttr \"y\" \"\\000\" <file3 >file1 &&\n \trm -f file2 &&\n \tgit update-index --add --remove file1 file2 file3 file4 &&\n \tgit commit -m \"Second Version\" &&\n@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '\n \ttest -z \"$(git diff --name-status binary -- file3)\"\n '\n \n-test_expect_success 'reject truncated binary diff' '\n+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '\n \tdo_reset &&\n \n \t# this length is calculated to get us very close to\ndiff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh\nindex 6f414ad27f5..1e7beab0016 100755\n--- a/t/t4116-apply-reverse.sh\n+++ b/t/t4116-apply-reverse.sh\n@@ -10,23 +10,17 @@ test_description='git apply in reverse\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping apply reverse tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success setup '\n \n \ttest_write_lines a b c d e f g h i j k l m n >file1 &&\n-\tperl -pe \"y/ijk/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"ijk\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit add file1 file2 &&\n \tgit commit -m initial &&\n \tgit tag initial &&\n \n \ttest_write_lines a b c g h i J K L m o n p q >file1 &&\n-\tperl -pe \"y/mon/\\\\000\\\\001\\\\002/\" <file1 >file2 &&\n+\ttr \"mon\" \"\\000\\001\\002\" <file1 >file2 &&\n \n \tgit commit -a -m second &&\n \tgit tag second &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 50fe8b0fd05..7fcca9ddad5 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '\n \n test_expect_success 'rerere clear' '\n \tmv $rr/postimage .git/post-saved &&\n-\techo \"$sha1\ta1\" | perl -pe \"y/\\012/\\000/\" >.git/MERGE_RR &&\n+\techo \"$sha1\ta1\" | tr \"\\012\" \"\\000\" >.git/MERGE_RR &&\n \tgit rerere clear &&\n \t! test -d $rr\n '\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515556","messageId":"20250403-b4-pks-t-perlless-v4-11-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 11/20] t: refactor tests depending on Perl substitution operator","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:02Z","receivedAt":"2025-04-03T05:06:11Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a bunch of tests that use Perl to perform substitution via the\n\"s/\" operator. These usecases can be trivially replaced with sed(1) and\ntr(1).\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0008-ignores.sh                        | 10 ++--------\n t/t4029-diff-trailing-space.sh            |  5 +++--\n t/t4200-rerere.sh                         | 12 +++---------\n t/t5303-pack-corruption-resilience.sh     | 10 ++++++----\n t/t5310-pack-bitmaps.sh                   |  4 ++--\n t/t5534-push-signed.sh                    |  4 ++--\n t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------\n t/t7416-submodule-dash-url.sh             |  9 ++-------\n t/t7508-status.sh                         |  4 ++--\n t/t8006-blame-textconv.sh                 |  8 +-------\n t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------\n 11 files changed, 40 insertions(+), 60 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex 1aaa6bf5ae8..273d71411fe 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -5,12 +5,6 @@ test_description=check-ignore\n TEST_CREATE_REPO_NO_TEMPLATE=1\n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping ignores tests; Perl not available'\n-\ttest_done\n-fi\n-\n init_vars () {\n \tglobal_excludes=\"global-excludes\"\n }\n@@ -45,11 +39,11 @@ test_stderr () {\n }\n \n broken_c_unquote () {\n-\t\"$PERL_PATH\" -pe 's/^\"//; s/\\\\//; s/\"$//; tr/\\n/\\0/' \"$@\"\n+\tsed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr '\\n' '\\0'\n }\n \n broken_c_unquote_verbose () {\n-\t\"$PERL_PATH\" -pe 's/\t\"/\t/; s/\\\\//; s/\"$//; tr/:\\t\\n/\\0/' \"$@\"\n+\tsed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' \"$1\" | tr ':\\t\\n' '\\000'\n }\n \n stderr_contains () {\ndiff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh\nindex a92a42990b1..90cdde88d8b 100755\n--- a/t/t4029-diff-trailing-space.sh\n+++ b/t/t4029-diff-trailing-space.sh\n@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644\n EOF\n exit 1\n \n-test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n+test_expect_success \"$test_description\" '\n \tprintf \"\\nx\\n\" > f &&\n \tbefore=$(git hash-object f) &&\n \tbefore=$(git rev-parse --short $before) &&\n@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS \"$test_description\" '\n \tgit config --bool diff.suppressBlankEmpty true &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\n-\tperl -i.bak -p -e \"s/^\\$/ /\" exp &&\n+\tsed \"s/^\\$/ /\" exp >exp.munged &&\n+\tmv exp.munged exp &&\n \tgit config --bool diff.suppressBlankEmpty false &&\n \tgit diff f > actual &&\n \ttest_cmp exp actual &&\ndiff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh\nindex 7fcca9ddad5..204325f4d53 100755\n--- a/t/t4200-rerere.sh\n+++ b/t/t4200-rerere.sh\n@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rerere tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tcat >a1 <<-\\EOF &&\n \tSome title\n@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '\n \ttest_might_fail git config --unset rerere.enabled &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep \"^=======\\$\" $rr/preimage &&\n \t! test -f $rr/postimage &&\n@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n \n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1 &&\n \tgrep ^=======$ $rr/preimage\n '\n@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '\n \tgit config rerere.enabled true &&\n \tgit reset --hard &&\n \ttest_must_fail git merge first &&\n-\tsha1=$(perl -pe \"s/\t.*//\" .git/MERGE_RR) &&\n+\tsha1=$(sed \"s/\t.*//\" .git/MERGE_RR) &&\n \trr=.git/rr-cache/$sha1\n '\n \ndiff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh\nindex ac5e370e1e4..ab99c8b6850 100755\n--- a/t/t5303-pack-corruption-resilience.sh\n+++ b/t/t5303-pack-corruption-resilience.sh\n@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '\n+test_expect_success 'create corruption in data of first object' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ base /abcdef/\" ${pack}.pack &&\n+\tsed \"s/ base /abcdef/\" ${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \ttest_must_fail git cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\n@@ -156,11 +157,12 @@ test_expect_success '... and then a repack \"clears\" the corruption' '\n \tgit cat-file blob $blob_3 > /dev/null\n '\n \n-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '\n+test_expect_success 'create corruption in data of first delta' '\n \tcreate_new_pack &&\n \tgit prune-packed &&\n \tchmod +w ${pack}.pack &&\n-\tperl -i.bak -pe \"s/ delta1 /abcdefgh/\" ${pack}.pack &&\n+\tsed \"s/ delta1 /abcdefgh/\" ${pack}.pack >${pack}.pack.munged &&\n+\tmv ${pack}.pack.munged ${pack}.pack &&\n \tgit cat-file blob $blob_1 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_2 > /dev/null &&\n \ttest_must_fail git cat-file blob $blob_3 > /dev/null\ndiff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh\nindex 81987296235..a62b463eaf0 100755\n--- a/t/t5310-pack-bitmaps.sh\n+++ b/t/t5310-pack-bitmaps.sh\n@@ -395,7 +395,7 @@ test_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -421,7 +421,7 @@ test_bitmap_cases () {\n \n \t\t\t# mark the commits which did not receive bitmaps as preferred,\n \t\t\t# and generate the bitmap again\n-\t\t\tperl -pe \"s{^}{create refs/tags/include/$. }\" <before |\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n \t\t\t\tgit update-ref --stdin &&\n \t\t\tgit -c pack.preferBitmapTips=refs/tags/include repack -adb &&\n \ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 342d0423c92..2a782214ee1 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \ttest_cmp expect dst/push-cert-status\n '\n \n-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '\n+test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \t# First, invoke receive-pack with dummy input to obtain its preamble.\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p\n \t# Tweak the push output to make the push option outside the cert\n \t# different, then replay it on a fresh dst, checking that ff is not\n \t# deleted.\n-\tperl -pe \"s/([^ ])bar/\\$1baz/\" push >push.tweak &&\n+\tsed \"s/\\([^ ]\\)bar/\\1baz/\" push >push.tweak &&\n \tprepare_dst &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n \tgit -C dst config receive.advertisepushoptions 1 &&\ndiff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh\nindex 6131c361094..b6f3344dbfb 100755\n--- a/t/t6011-rev-list-with-bad-commit.sh\n+++ b/t/t6011-rev-list-with-bad-commit.sh\n@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list with bad commit tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Note:\n # - compression level is set to zero to make \"corruptions\" easier to perform\n # - reflog is disabled to avoid extra references which would twart the test\n@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \\\n    first_commit=$(git rev-parse HEAD~3)\n    '\n \n-test_expect_success 'corrupt second commit object' \\\n-   '\n-   perl -i.bak -pe \"s/second commit/socond commit/\" .git/objects/pack/*.pack &&\n-   test_must_fail git fsck --full\n-   '\n+test_expect_success 'corrupt second commit object' '\n+\tfor p in .git/objects/pack/*.pack\n+\tdo\n+\t\tsed \"s/second commit/socond commit/\" \"$p\" >\"$p.munged\" &&\n+\t\tmv \"$p.munged\" \"$p\" ||\n+\t\treturn 1\n+\tdone &&\n+\ttest_must_fail git fsck --full\n+'\n \n test_expect_success 'rev-list should fail' '\n \ttest_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null\ndiff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh\nindex 14069600a2f..3d944a00e0d 100755\n--- a/t/t7416-submodule-dash-url.sh\n+++ b/t/t7416-submodule-dash-url.sh\n@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping submodule dash URL tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \tgit config --global protocol.file.allow always\n '\n@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '\n '\n \n test_expect_success 'remove ./ protection from .gitmodules url' '\n-\tperl -i -pe \"s{\\./}{}\" .gitmodules &&\n+\tsed \"s|\\./||\" .gitmodules >.gitmodules.munged &&\n+\tmv .gitmodules.munged .gitmodules &&\n \tgit commit -am \"drop protection\"\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 14c41b2cb7c..cdc1d6fcc78 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '\n \ttest_cmp expect output\n '\n \n-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '\n+test_expect_success 'status -z implies porcelain' '\n \tgit status --porcelain |\n-\tperl -pe \"s/\\012/\\000/g\" >expect &&\n+\ttr \"\\012\" \"\\000\" >expect &&\n \tgit status -z >output &&\n \ttest_cmp expect output\n '\ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 5cb16872081..db1e2afb2ca 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -4,12 +4,6 @@ test_description='git blame textconv support'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping blame textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_blame() {\n \tsed -e 's/^[^(]*//'\n }\n@@ -17,7 +11,7 @@ find_blame() {\n cat >helper <<'EOF'\n #!/bin/sh\n grep -q '^bin: ' \"$1\" || { echo \"E: $1 is not \\\"binary\\\" file\" 1>&2; exit 1; }\n-\"$PERL_PATH\" -p -e 's/^bin: /converted: /' \"$1\"\n+sed 's/^bin: /converted: /' \"$1\"\n EOF\n chmod +x helper\n \ndiff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh\nindex a9d38be997c..b57a362bb98 100755\n--- a/t/t9137-git-svn-dcommit-clobber-series.sh\n+++ b/t/t9137-git-svn-dcommit-clobber-series.sh\n@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '\n \ttest -e file\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '\n+test_expect_success '(supposedly) non-conflicting change from SVN' '\n \ttest x\"$(sed -n -e 58p < file)\" = x58 &&\n \ttest x\"$(sed -n -e 61p < file)\" = x61 &&\n \tsvn_cmd co \"$svnrepo\" tmp &&\n \t(cd tmp &&\n-\t\tperl -i.bak -p -e \"s/^58$/5588/\" file &&\n-\t\tperl -i.bak -p -e \"s/^61$/6611/\" file &&\n+\t\tsed -e \"s/^58$/5588/\" -e \"s/^61$/6611/\" file >file.munged &&\n+\t\tmv file.munged file &&\n \t\tpoke file &&\n \t\ttest x\"$(sed -n -e 58p < file)\" = x5588 &&\n \t\ttest x\"$(sed -n -e 61p < file)\" = x6611 &&\n@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' \"\n \tgit commit -m bye-life life\n \t\"\n \n-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' \"\n+test_expect_success 'change file but in unrelated area' \"\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7 &&\n-\tperl -i.bak -p -e 's/^4\\$/4444/' file &&\n-\tperl -i.bak -p -e 's/^7\\$/7777/' file &&\n+\tsed -e 's/^4\\$/4444/' \\\n+\t    -e 's/^7\\$/7777/' \\\n+\t\tfile >file.munged &&\n+\tmv file.munged file &&\n \ttest x\\\"\\$(sed -n -e 4p < file)\\\" = x4444 &&\n \ttest x\\\"\\$(sed -n -e 7p < file)\\\" = x7777 &&\n \tgit commit -m '4 => 4444, 7 => 7777' file &&\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515557","messageId":"20250403-b4-pks-t-perlless-v4-13-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 13/20] t: refactor tests depending on Perl for textconv scripts","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:04Z","receivedAt":"2025-04-03T05:06:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have a couple of tests that depend on Perl for textconv scripts.\nRefactor these tests to instead be implemented via shell utilities so\nthat we can drop a couple of PERL_TEST_HELPERS prerequisites.\n\nNote that the conversion in t4030 is not a one-to-one equivalent to the\nprevious textconv script. Before this change we used to essentially do a\nhexdump via Perl. The obvious conversion here would be to use `test-tool\nhexdump` like we do for the other tests. But this would lead to a ripple\neffect where we would have to adapt a bunch of other tests with a bunch\nof seemingly unrelated changes, which would be somewhat awkward.\n\nInstead, we're going with the minimum viable change: the test files we\nwrite contain \"\\001\" and \"\\000\", and the test's expectation is that\nthose get translated into proper ASCII characters. So instead of doing a\nfull hexdump, we simply use tr(1) to translate these specific bytes.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t4030-diff-textconv.sh       | 15 +++------------\n t/t4031-diff-rewrite-binary.sh | 19 +++++++------------\n t/t7815-grep-binary.sh         | 15 +++------------\n 3 files changed, 13 insertions(+), 36 deletions(-)\n\ndiff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh\nindex c7d8eb12453..f904fc19f69 100755\n--- a/t/t4030-diff-textconv.sh\n+++ b/t/t4030-diff-textconv.sh\n@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping diff textconv tests; Perl not available'\n-\ttest_done\n-fi\n-\n find_diff() {\n \tsed '1,/^index /d' | sed '/^-- $/,$d'\n }\n@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'\n +1\n EOF\n \n-cat >hexdump <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-chmod +x hexdump\n-\n test_expect_success 'setup binary file with history' '\n+\twrite_script hexdump <<-\\EOF &&\n+\ttr \"\\000\\001\" \"01\" <\"$1\"\n+\tEOF\n \ttest_commit --printf one file \"\\\\0\\\\n\" &&\n \ttest_commit --printf --append two file \"\\\\01\\\\n\"\n '\ndiff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh\nindex cbe50b15772..15e012ccc7c 100755\n--- a/t/t4031-diff-rewrite-binary.sh\n+++ b/t/t4031-diff-rewrite-binary.sh\n@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '\n \tgrep \" rewrite file\" diff\n '\n \n-{\n-\techo \"#!$SHELL_PATH\"\n-\tcat <<'EOF'\n-\"$PERL_PATH\" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < \"$1\"\n-EOF\n-} >dump\n-chmod +x dump\n-\n test_expect_success 'setup textconv' '\n+\twrite_script dump <<-\\EOF &&\n+\ttest-tool hexdump <\"$1\"\n+\tEOF\n \techo file diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/dump\n '\n \n-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '\n+test_expect_success 'rewrite diff respects textconv' '\n \tgit diff -B >diff &&\n-\tgrep \"dissimilarity index\" diff &&\n-\tgrep \"^-61\" diff &&\n-\tgrep \"^-0\" diff\n+\ttest_grep \"dissimilarity index\" diff &&\n+\ttest_grep \"^-3d 0a 00\" diff &&\n+\ttest_grep \"^+3d 0a 01\" diff\n '\n \n test_done\ndiff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh\nindex b2730d200c8..3bd91da9707 100755\n--- a/t/t7815-grep-binary.sh\n+++ b/t/t7815-grep-binary.sh\n@@ -4,12 +4,6 @@ test_description='git grep in binary files'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping grep binary tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' \"\n \techo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&\n \tgit add a &&\n@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '\n \ttest_cmp expect actual\n '\n \n-cat >nul_to_q_textconv <<'EOF'\n-#!/bin/sh\n-\"$PERL_PATH\" -pe 'y/\\000/Q/' < \"$1\"\n-EOF\n-chmod +x nul_to_q_textconv\n-\n test_expect_success 'setup textconv filters' '\n+\twrite_script nul_to_q_textconv <<-\\EOF &&\n+\ttr \"\\000\" \"Q\" <\"$1\"\n+\tEOF\n \techo a diff=foo >.gitattributes &&\n \tgit config diff.foo.textconv \"\\\"$(pwd)\\\"\"/nul_to_q_textconv\n '\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515558","messageId":"20250403-b4-pks-t-perlless-v4-14-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:05Z","receivedAt":"2025-04-03T05:06:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from\nstdin. Refactor it to instead use sed(1) so that we drop the\nPERL_TEST_HELPERS prerequisite in users of this library.\n\nNote that we have to add PERL_TEST_HELPERS to a subset of tests in t6300\nnow that the test suite doesn't bail out early anymore in case the\nprerequisite isn't set.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-gpg.sh            |  6 +-----\n t/t6300-for-each-ref.sh | 21 ++++++++++-----------\n 2 files changed, 11 insertions(+), 16 deletions(-)\n\ndiff --git a/t/lib-gpg.sh b/t/lib-gpg.sh\nindex 3845b6ac449..937b876bd05 100644\n--- a/t/lib-gpg.sh\n+++ b/t/lib-gpg.sh\n@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '\n '\n \n sanitize_pgp() {\n-\tperl -ne '\n-\t\t/^-----END PGP/ and $in_pgp = 0;\n-\t\tprint unless $in_pgp;\n-\t\t/^-----BEGIN PGP/ and $in_pgp = 1;\n-\t'\n+\tsed \"/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}\"\n }\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 732a4d3171e..5db7038c417 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping for-each-ref tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Mon Jul 3 23:18:43 2006 +0000\n datestamp=1151968723\n setdate_and_increment () {\n@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '\n \ttest_must_fail git for-each-ref --format=\"%(raw)\" --tcl\n '\n \n-test_expect_success '%(raw) with --perl' '\n+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '\n \tgit for-each-ref --format=\"\\$name= %(raw);\n print \\\"\\$name\\\"\" refs/myblobs/blob1 --perl | perl >actual &&\n \tcmp blob1 actual &&\n@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '\n '\n \n test_trailer_option () {\n+\tif test \"$#\" -eq 3\n+\tthen\n+\t\tprereq=\"$1\"\n+\t\tshift\n+\tfi &&\n \ttitle=$1 option=$2\n \tcat >expect\n-\ttest_expect_success \"$title\" '\n+\ttest_expect_success $prereq \"$title\" '\n \t\tgit for-each-ref --format=\"%($option)\" refs/heads/main >actual &&\n \t\ttest_cmp expect actual &&\n \t\tgit for-each-ref --format=\"%(contents:$option)\" refs/heads/main >actual &&\n@@ -1452,7 +1451,7 @@ test_trailer_option () {\n \t'\n }\n \n-test_trailer_option '%(trailers:unfold) unfolds trailers' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \\\n \t'trailers:unfold' <<-EOF\n \t$(unfold <trailers)\n \n@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \\\n \n \tEOF\n \n-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \\\n \t'trailers:only,unfold' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n \tEOF\n \n-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \\\n+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \\\n \t'trailers:unfold,only' <<-EOF\n \t$(grep -v patch.description <trailers | unfold)\n \n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515559","messageId":"20250403-b4-pks-t-perlless-v4-12-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:03Z","receivedAt":"2025-04-03T05:06:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"A bunch of tests rely on Perl to print data in various different ways.\nThese usages fall into the following categories:\n\n  - Print data conditionally by matching patterns. These usecases can be\n    converted to use awk(1) rather easily.\n\n  - Print data repeatedly. These usecases can typically be converted to\n    use a combination of `test-tool genzeros` and sed(1).\n\n  - Print data in reverse. These usecases can be converted to use\n    awk(1) or `sort -r`.\n\nRefactor the tests accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0610-reftable-basics.sh          |  7 +++----\n t/t0613-reftable-write-options.sh   |  4 ++--\n t/t1010-mktree.sh                   |  8 ++++----\n t/t4150-am.sh                       | 10 +++++-----\n t/t5300-pack-object.sh              | 16 +++++-----------\n t/t5326-multi-pack-bitmaps.sh       |  6 +++---\n t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------\n t/t5410-receive-pack-alternates.sh  |  6 +++---\n t/t5701-git-serve.sh                |  7 +++++--\n t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------\n t/t6115-rev-list-du.sh              |  8 +-------\n t/t7006-pager.sh                    |  8 ++++----\n t/t8002-blame.sh                    |  2 +-\n t/t9850-shell.sh                    |  4 ++--\n 14 files changed, 51 insertions(+), 67 deletions(-)\n\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex 5e0a1fa176d..77ed11e7172 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '\n \ttest_cmp actual expect\n '\n \n-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '\n+test_expect_success 'basic: can write large commit message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+\n+\tawk \"BEGIN { for (i = 0; i < 50000; i++) printf \\\"%s\\\", \\\"this is a long commit message\\\" }\" >commit-msg &&\n \tgit -C repo commit --allow-empty --file=../commit-msg\n '\n \ndiff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh\nindex fa1e2f9eef8..42aa1592f87 100755\n--- a/t/t0613-reftable-write-options.sh\n+++ b/t/t0613-reftable-write-options.sh\n@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '\n+test_expect_success 'small block size fails with large reflog message' '\n \ttest_when_finished \"rm -rf repo\" &&\n \tgit init repo &&\n \t(\n \t\tcd repo &&\n \t\ttest_commit A &&\n-\t\tperl -e \"print \\\"a\\\" x 500\" >logmsg &&\n+\t\ttest-tool genzeros 500 | tr \"\\000\" \"a\" >logmsg &&\n \t\tcat >expect <<-EOF &&\n \t\tfatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large\n \t\tEOF\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex 4977998e205..e9973f74949 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '\n \ttest_cmp tree.withsub actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '\n-\tperl -e \"print reverse <>\" <top |\n+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '\n+\tsort -r <top |\n \tgit mktree >actual &&\n \ttest_cmp tree actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '\n-\tperl -e \"print reverse <>\" <top.withsub |\n+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '\n+\tsort -r <top.withsub |\n \tgit mktree >actual &&\n \ttest_cmp tree.withsub actual\n '\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 4794510d70d..2ae93d3c967 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n \ttest_cmp msg out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n+test_expect_success 'am works with multi-line in-body headers' '\n \tFORTY=\"String that has a length of more than forty characters\" &&\n \tLONG=\"$FORTY $FORTY\" &&\n \trm -fr .git/rebase-apply &&\n@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'\n     Body test\" --author=\"$LONG <long@example.com>\" &&\n \tgit format-patch --stdout -1 >patch &&\n \t# bump from, date, and subject down to in-body header\n-\tperl -lpe \"\n-\t\tif (/^From:/) {\n+\tawk \"\n+\t\t/^From:/{\n \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n \t\t\tprint \\\"Subject: x\\n\\\";\n-\t\t}\n-\t\" patch >msg &&\n+\t\t}; 1\n+\t\" <patch >msg &&\n \tgit checkout HEAD^ &&\n \tgit am msg &&\n \t# Ensure that the author and full message are present\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 143856c29f1..a5932b6a8be 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -7,17 +7,11 @@ test_description='git pack-object'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pack-object tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_expect_success 'setup' '\n \trm -f .git/index* &&\n-\tperl -e \"print \\\"a\\\" x 4096;\" >a &&\n-\tperl -e \"print \\\"b\\\" x 4096;\" >b &&\n-\tperl -e \"print \\\"c\\\" x 4096;\" >c &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"a\" >a &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"b\" >b &&\n+\ttest-tool genzeros 4096 | tr \"\\000\" \"c\" >c &&\n \ttest-tool genrandom \"seed a\" 2097152 >a_big &&\n \ttest-tool genrandom \"seed b\" 2097152 >b_big &&\n \tgit update-index --add a a_big b b_big c &&\n@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'\n # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>\n # e.g.: check_deltas stderr -gt 0\n check_deltas() {\n-\tdeltas=$(perl -lne '/delta (\\d+)/ and print $1' \"$1\") &&\n+\tdeltas=$(sed -n 's/Total [0-9][0-9]* (delta \\([0-9][0-9]*\\)).*/\\1/p' \"$1\") &&\n \tshift &&\n \tif ! test \"$deltas\" \"$@\"\n \tthen\n@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '\n \tcheck_unpack test-3-${packname_3} obj-list \"$BATCH_CONFIGURATION\"\n '\n \n-test_expect_success 'compare delta flavors' '\n+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '\n \tperl -e '\\''\n \t\tdefined($_ = -s $_) or die for @ARGV;\n \t\texit 1 if $ARGV[0] <= $ARGV[1];\ndiff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh\nindex 627f8b4efdc..892aeb09e4b 100755\n--- a/t/t5326-multi-pack-bitmaps.sh\n+++ b/t/t5326-multi-pack-bitmaps.sh\n@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {\n \t\t)\n \t'\n \n-\ttest_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '\n+\ttest_expect_success 'pack.preferBitmapTips' '\n \t\tgit init repo &&\n \t\ttest_when_finished \"rm -fr repo\" &&\n \t\t(\n@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {\n \t\t\tcomm -13 bitmaps commits >before &&\n \t\t\ttest_line_count = 1 before &&\n \n-\t\t\tperl -ne \"printf(\\\"create refs/tags/include/%d \\\", $.); print\" \\\n-\t\t\t\t<before | git update-ref --stdin &&\n+\t\t\tsed \"s|\\(.*\\)|create refs/tags/include/\\1 \\1|\" before |\n+\t\t\tgit update-ref --stdin &&\n \n \t\t\trm -fr $midx-$(midx_checksum $objdir).bitmap &&\n \t\t\trm -fr $midx &&\ndiff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\nindex 1059ff45fe4..56674db562f 100755\n--- a/t/t5333-pseudo-merge-bitmaps.sh\n+++ b/t/t5333-pseudo-merge-bitmaps.sh\n@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n-\ttest_done\n-fi\n-\n test_pseudo_merges () {\n \ttest-tool bitmap dump-pseudo-merges\n }\n@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {\n \n tag_everything () {\n \tgit rev-list --all --no-object-names >in &&\n-\tperl -lne '\n-\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n-\t' <in | git update-ref --stdin\n+\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' in |\n+\tgit update-ref --stdin\n }\n \n test_expect_success 'setup' '\n@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n \ttest_config bitmapPseudoMerge.test.pattern \"refs/tags/\" &&\n \ttest_config bitmapPseudoMerge.test.maxMerges 1 &&\n \ttest_config bitmapPseudoMerge.test.stableThreshold never &&\n@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\t\ttest_commit_bulk 16 &&\n \n \t\t\tgit rev-list HEAD~16.. >in &&\n-\n-\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n+\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n \t\t\tgit update-ref --stdin || return 1\n \t\tdone &&\n \n@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\tdo\n \t\t\ttest_pseudo_merge_commits $m >oids &&\n \t\t\tgrep -f oids refs |\n-\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n+\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n \t\t\tsort -u || return 1\n \t\tdone >remotes &&\n \ndiff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh\nindex 6a009fdcd71..4e82fd102e3 100755\n--- a/t/t5410-receive-pack-alternates.sh\n+++ b/t/t5410-receive-pack-alternates.sh\n@@ -17,10 +17,10 @@ test_expect_success 'setup' '\n '\n \n extract_haves () {\n-\tdepacketize | perl -lne '/^(\\S+) \\.have/ and print $1'\n+\tdepacketize | sed -n 's/^\\([^ ][^ ]*\\) \\.have/\\1/p'\n }\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n+test_expect_success 'with core.alternateRefsCommand' '\n \twrite_script fork/alternate-refs <<-\\EOF &&\n \t\tgit --git-dir=\"$1\" for-each-ref \\\n \t\t\t--format=\"%(objectname)\" \\\n@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '\n \ttest_cmp expect actual.haves\n '\n \n-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '\n+test_expect_success 'with core.alternateRefsPrefixes' '\n \ttest_config -C fork core.alternateRefsPrefixes \"refs/heads/private\" &&\n \tgit rev-parse private/branch >expect &&\n \tprintf \"0000\" | git receive-pack fork >actual &&\ndiff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh\nindex 200bf06ecb3..d4c28bae39e 100755\n--- a/t/t5701-git-serve.sh\n+++ b/t/t5701-git-serve.sh\n@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n+test_expect_success 'ignore very large set of prefixes' '\n \t# generate a large number of ref-prefixes that we expect\n \t# to match nothing; the value here exceeds TOO_MANY_PREFIXES\n \t# from ls-refs.c.\n@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '\n \t\techo command=ls-refs &&\n \t\techo object-format=$(test_oid algo) &&\n \t\techo 0001 &&\n-\t\tperl -le \"print \\\"ref-prefix refs/heads/\\$_\\\" for (1..65536)\" &&\n+\t\tawk \"{\n+\t\t\tfor (i = 1; i <= 65536; i++)\n+\t\t\t\tprint \\\"ref-prefix refs/heads/\\\", \\$i\n+\t\t}\" &&\n \t\techo 0000\n \t} |\n \ttest-tool pkt-line pack >in &&\ndiff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh\nindex 8074185742c..273196f52b5 100755\n--- a/t/t6013-rev-list-reverse-parents.sh\n+++ b/t/t6013-rev-list-reverse-parents.sh\n@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '\n \tcommit five\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '\n-\tgit rev-list --parents --full-history main -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+reverse () {\n+\tawk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'\n+}\n+\n+test_expect_success '--reverse --parents --full-history combines correctly' '\n+\tgit rev-list --parents --full-history main -- foo | reverse >expected &&\n \tgit rev-list --reverse --parents --full-history main -- foo \\\n \t\t> actual &&\n \ttest_cmp expected actual\n \t'\n \n-test_expect_success PERL_TEST_HELPERS '--boundary does too' '\n-\tgit rev-list --boundary --parents --full-history main ^root -- foo |\n-\t\tperl -e \"print reverse <>\" > expected &&\n+test_expect_success '--boundary does too' '\n+\tgit rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&\n \tgit rev-list --boundary --reverse --parents --full-history \\\n \t\tmain ^root -- foo > actual &&\n \ttest_cmp expected actual\ndiff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh\nindex 6a74be576a2..04c577dad69 100755\n--- a/t/t6115-rev-list-du.sh\n+++ b/t/t6115-rev-list-du.sh\n@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list disk usage tests; Perl not available'\n-\ttest_done\n-fi\n-\n # we want a mix of reachable and unreachable, as well as\n # objects in the bitmapped pack and some outside of it\n test_expect_success 'set up repository' '\n@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '\n disk_usage_slow () {\n \tgit rev-list --no-object-names \"$@\" |\n \tgit cat-file --batch-check=\"%(objectsize:disk)\" |\n-\tperl -lne '$total += $_; END { print $total}'\n+\tawk '{ i += $1 } END { print i }'\n }\n \n # check behavior with given rev-list options; note that\ndiff --git a/t/t7006-pager.sh b/t/t7006-pager.sh\nindex 49aae183829..9717e825f0d 100755\n--- a/t/t7006-pager.sh\n+++ b/t/t7006-pager.sh\n@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '\n \texport GIT_TRACE2_BRIEF\n '\n \n-test_expect_success PERL_TEST_HELPERS 'setup large log output' '\n-\tperl -e \"\n-\t\tprint \\\"this is a long commit message\\\" x 50000\n-\t\" >commit-msg &&\n+test_expect_success 'setup large log output' '\n+\ttest-tool genzeros 50000 |\n+\ttr \"\\000\" \"a\" |\n+\tsed \"s/a/this is a long commit message/g\" >commit-msg &&\n \tgit commit --allow-empty -F commit-msg\n '\n \ndiff --git a/t/t8002-blame.sh b/t/t8002-blame.sh\nindex b40199df231..7822947f028 100755\n--- a/t/t8002-blame.sh\n+++ b/t/t8002-blame.sh\n@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '\n \t\texpect=$1 && shift &&\n \t\techo $sha1 | cut -c 1-$expect >expect &&\n \t\tgit blame \"$@\" abbrev.t >actual &&\n-\t\tperl -lne \"/[0-9a-f]+/ and print \\$&\" <actual >actual.sha &&\n+\t\tsed -n \"s/^[\\^]\\{0,1\\}\\([0-9a-f][0-9a-f]*\\).*/\\1/p\" actual >actual.sha &&\n \t\ttest_cmp expect actual.sha\n \t}\n '\ndiff --git a/t/t9850-shell.sh b/t/t9850-shell.sh\nindex f619b60f226..21c3af48bd0 100755\n--- a/t/t9850-shell.sh\n+++ b/t/t9850-shell.sh\n@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '\n-\tperl -e \"print \\\"a\\\" x 2**12 for (0..2**19)\" |\n+test_expect_success 'shell complains of overlong commands' '\n+\ttest-tool genzeros | tr \"\\000\" \"a\" |\n \ttest_must_fail git shell 2>err &&\n \tgrep \"too long\" err\n '\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515560","messageId":"20250403-b4-pks-t-perlless-v4-15-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:06Z","receivedAt":"2025-04-03T05:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `name_from_description()` test helper uses Perl to munge a given\ndescription and convert it into a name. Refactor it to instead use a\ncombination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS\nprerequisites in users of this library.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-t6000.sh                 | 13 ++++++-------\n t/t6002-rev-list-bisect.sh     |  6 ------\n t/t6003-rev-list-topo-order.sh |  6 ------\n 3 files changed, 6 insertions(+), 19 deletions(-)\n\ndiff --git a/t/lib-t6000.sh b/t/lib-t6000.sh\nindex fba6778ca35..35c54724650 100644\n--- a/t/lib-t6000.sh\n+++ b/t/lib-t6000.sh\n@@ -109,13 +109,12 @@ check_output () {\n # All alphanums translated into -'s which are then compressed and stripped\n # from front and back.\n name_from_description () {\n-\tperl -pe '\n-\t\ts/[^A-Za-z0-9.]/-/g;\n-\t\ts/-+/-/g;\n-\t\ts/-$//;\n-\t\ts/^-//;\n-\t\ty/A-Z/a-z/;\n-\t'\n+\tsed \\\n+\t\t-e 's/[^A-Za-z0-9.]/-/g' \\\n+\t\t-e 's/--*/-/g' \\\n+\t\t-e 's/-$//' \\\n+\t\t-e 's/^-//' \\\n+\t\t-e 'y/A-Z/a-z/'\n }\n \n \ndiff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh\nindex 5e1482aff78..daa009c9a1b 100755\n--- a/t/t6002-rev-list-bisect.sh\n+++ b/t/t6002-rev-list-bisect.sh\n@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list bisect tests; Perl not available'\n-\ttest_done\n-fi\n-\n # usage: test_bisection max-diff bisect-option head ^prune...\n #\n # e.g. test_bisection 1 --bisect l1 ^l0\ndiff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh\nindex 02dd4127aff..0d7055d46d4 100755\n--- a/t/t6003-rev-list-topo-order.sh\n+++ b/t/t6003-rev-list-topo-order.sh\n@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-t6000.sh # t6xxx specific functions\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping rev-list topo-order tests; Perl not available'\n-\ttest_done\n-fi\n-\n list_duplicates()\n {\n     \"$@\" | sort | uniq -d\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515561","messageId":"20250403-b4-pks-t-perlless-v4-17-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:08Z","receivedAt":"2025-04-03T05:06:14Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `generate_random_characters()` helper function generates N\nrandom characters in the range 'a-z' and writes them into a file. The\nlogic currently uses Perl, but it can be adapted rather easily by:\n\n  - Making `test-tool genrandom` generate an infinite stream.\n\n  - Using `tr -dc` to strip all characters which aren't in the range of\n    'a-z'.\n\n  - Using `test_copy_bytes()` to copy the first N bytes.\n\nThis allows us to drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0021-conversion.sh | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 4a892a91780..bf10d253ec4 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -20,8 +20,7 @@ EOF\n generate_random_characters () {\n \tLEN=$1\n \tNAME=$2\n-\ttest-tool genrandom some-seed $LEN |\n-\t\tperl -pe \"s/./chr((ord($&) % 26) + ord('a'))/sge\" >\"$TEST_ROOT/$NAME\"\n+\ttest-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes \"$LEN\" >\"$TEST_ROOT/$NAME\"\n }\n \n filter_git () {\n@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for \"clean\" ope\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '\n+test_expect_success 'required process filter should process multiple packets' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \n@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu\n \t)\n '\n \n-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '\n+test_expect_success 'required process filter with clean error should fail' '\n \ttest_config_global filter.protocol.process \"test-tool rot13-filter --log=debug.log clean smudge\" &&\n \ttest_config_global filter.protocol.required true &&\n \trm -rf repo &&\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515562","messageId":"20250403-b4-pks-t-perlless-v4-16-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 16/20] t/lib-httpd: refactor \"one-time-perl\" CGI script to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:07Z","receivedAt":"2025-04-03T05:06:14Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our Apache HTTPD setup exposes an \"one_time_perl\" endpoint to access\nrepositories. If used, we execute the \"apply-one-time-perl.sh\" CGI\nscript that checks whether we have a \"one-time-perl\" script. If so, that\nscript gets executed so that it can munge what would be served. Once\ndone, the script gets removed so that it doesn't execute a second time.\n\nAs the name says, this functionality expects the user to pass a Perl\nscript. This isn't really necessary though: we can just as easily\nimplement the same thing with arbitrary scripts.\n\nRefactor the code so that we instead expect an arbitrary script to\nexist and rename the functionality to \"one-time-script\". Adapt callers\nto use shell utilities instead of Perl so that we can drop the\nPERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/lib-httpd.sh                       |  2 +-\n t/lib-httpd/apache.conf              |  6 ++---\n t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------\n t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++\n t/t5537-fetch-shallow.sh             | 17 ++++++-------\n t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------\n t/t5702-protocol-v2.sh               | 27 +++++++++++---------\n t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---\n 8 files changed, 86 insertions(+), 77 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex d83bafeab32..5091db949b7 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -165,7 +165,7 @@ prepare_httpd() {\n \tinstall_script broken-smart-http.sh\n \tinstall_script error-smart-http.sh\n \tinstall_script error.sh\n-\tinstall_script apply-one-time-perl.sh\n+\tinstall_script apply-one-time-script.sh\n \tinstall_script nph-custom-auth.sh\n \n \tln -s \"$LIB_HTTPD_MODULE_PATH\" \"$HTTPD_ROOT_PATH/modules\"\ndiff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf\nindex 022276a6b9a..e631ab0eb5e 100644\n--- a/t/lib-httpd/apache.conf\n+++ b/t/lib-httpd/apache.conf\n@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n-<LocationMatch /one_time_perl/>\n+<LocationMatch /one_time_script/>\n \tSetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}\n \tSetEnv GIT_HTTP_EXPORT_ALL\n </LocationMatch>\n@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1\n ScriptAlias /broken_smart/ broken-smart-http.sh/\n ScriptAlias /error_smart/ error-smart-http.sh/\n ScriptAlias /error/ error.sh/\n-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1\n+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1\n ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Directory ${GIT_EXEC_PATH}>\n \tOptions FollowSymlinks\n@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1\n <Files error.sh>\n   Options ExecCGI\n </Files>\n-<Files apply-one-time-perl.sh>\n+<Files apply-one-time-script.sh>\n \tOptions ExecCGI\n </Files>\n <Files ${GIT_EXEC_PATH}/git-http-backend>\ndiff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh\ndeleted file mode 100644\nindex d7f9fed6aee..00000000000\n--- a/t/lib-httpd/apply-one-time-perl.sh\n+++ /dev/null\n@@ -1,27 +0,0 @@\n-#!/bin/sh\n-\n-# If \"one-time-perl\" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,\n-# using the contents of \"one-time-perl\" as the perl command to be run. If the\n-# response was modified as a result, delete \"one-time-perl\" so that subsequent\n-# HTTP responses are no longer modified.\n-#\n-# This can be used to simulate the effects of the repository changing in\n-# between HTTP request-response pairs.\n-if test -f one-time-perl\n-then\n-\tLC_ALL=C\n-\texport LC_ALL\n-\n-\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n-\t\"$PERL_PATH\" -pe \"$(cat one-time-perl)\" out >out_modified\n-\n-\tif cmp -s out out_modified\n-\tthen\n-\t\tcat out\n-\telse\n-\t\tcat out_modified\n-\t\trm one-time-perl\n-\tfi\n-else\n-\t\"$GIT_EXEC_PATH/git-http-backend\"\n-fi\ndiff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh\nnew file mode 100644\nindex 00000000000..b1682944e28\n--- /dev/null\n+++ b/t/lib-httpd/apply-one-time-script.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+# If \"one-time-script\" exists in $HTTPD_ROOT_PATH, run the script on the HTTP\n+# response. If the response was modified as a result, delete \"one-time-script\"\n+# so that subsequent HTTP responses are no longer modified.\n+#\n+# This can be used to simulate the effects of the repository changing in\n+# between HTTP request-response pairs.\n+if test -f one-time-script\n+then\n+\tLC_ALL=C\n+\texport LC_ALL\n+\n+\t\"$GIT_EXEC_PATH/git-http-backend\" >out\n+\t./one-time-script out >out_modified\n+\n+\tif cmp -s out out_modified\n+\tthen\n+\t\tcat out\n+\telse\n+\t\tcat out_modified\n+\t\trm one-time-script\n+\tfi\n+else\n+\t\"$GIT_EXEC_PATH/git-http-backend\"\n+fi\ndiff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh\nindex 77d20d19110..6588ce62264 100755\n--- a/t/t5537-fetch-shallow.sh\n+++ b/t/t5537-fetch-shallow.sh\n@@ -256,7 +256,7 @@ start_httpd\n \n REPO=\"$HTTPD_DOCUMENT_ROOT_PATH/repo\"\n \n-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '\n+test_expect_success 'shallow fetches check connectivity before writing shallow file' '\n \trm -rf \"$REPO\" client &&\n \n \tgit init \"$REPO\" &&\n@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before\n \tgit -C \"$REPO\" config protocol.version 2 &&\n \tgit -C client config protocol.version 2 &&\n \n-\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_perl/repo\" main:a_branch &&\n+\tgit -C client fetch --depth=2 \"$HTTPD_URL/one_time_script/repo\" main:a_branch &&\n \n \t# Craft a situation in which the server sends back an unshallow request\n \t# with an empty packfile. This is done by refetching with a shorter\n \t# depth (to ensure that the packfile is empty), and overwriting the\n \t# shallow line in the response with the unshallow line we want.\n-\tprintf \"$(test_oid perl)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD)\" \\\n-\t       \"$(git -C \"$REPO\" rev-parse HEAD^)\" \\\n-\t       >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF &&\n+\tsed \"$(printf \"$(test_oid perl)\" \"$(git -C \"$REPO\" rev-parse HEAD)\" \"$(git -C \"$REPO\" rev-parse HEAD^)\")\" \"\\$1\"\n+\tEOF\n \ttest_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \\\n-\t\tfetch --depth=1 \"$HTTPD_URL/one_time_perl/repo\" \\\n+\t\tfetch --depth=1 \"$HTTPD_URL/one_time_script/repo\" \\\n \t\tmain:a_branch &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\" &&\n \n \t# Ensure that the resulting repo is consistent, despite our failure to\n \t# fetch.\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex bc7e0fec8dc..1e354e057fa 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -737,21 +737,25 @@ intersperse () {\n \tsed 's/\\(..\\)/'$1'\\1/g'\n }\n \n-# Create a one-time-perl command to replace the existing packfile with $1.\n+# Create a one-time-script command to replace the existing packfile with $1.\n replace_packfile () {\n-\t# The protocol requires that the packfile be sent in sideband 1, hence\n-\t# the extra \\x01 byte at the beginning.\n-\tcp $1 \"$HTTPD_ROOT_PATH/one-time-pack\" &&\n-\techo 'if (/packfile/) {\n-\t\tprint;\n-\t\tmy $length = -s \"one-time-pack\";\n-\t\tprintf \"%04x\\x01\", $length + 5;\n-\t\tprint `cat one-time-pack` . \"0000\";\n-\t\tlast\n-\t}' >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\tcp \"$1\" one-time-pack &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tif grep packfile \"\\$1\" >/dev/null\n+\tthen\n+\t\tsed '/packfile/q' \"\\$1\" &&\n+\t\t# The protocol requires that the packfile be sent in sideband\n+\t\t# 1, hence the extra \\001 byte at the beginning.\n+\t\tprintf \"%04x\\001\" \\$((\\$(wc -c <\"$PWD/one-time-pack\") + 5)) &&\n+\t\tcat \"$PWD/one-time-pack\" &&\n+\t\tprintf \"0000\"\n+\telse\n+\t\tcat \"\\$1\"\n+\tfi\n+\tEOF\n }\n \n-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '\n+test_expect_success 'upon cloning, check that all refs point to objects' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t\n \t# section header.\n \ttest_config -C \"$SERVER\" protocol.version 2 &&\n \ttest_must_fail git -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&\n \n \ttest_grep \"did not send all necessary objects\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '\n+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '\n \tSERVER=\"$HTTPD_DOCUMENT_ROOT_PATH/server\" &&\n \trm -rf \"$SERVER\" repo &&\n \ttest_create_repo \"$SERVER\" &&\n@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not\n \n \t# Exercise to make sure it works.\n \tgit -c protocol.version=2 clone \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&\n \t! grep \"missing object referenced by\" err &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '\n@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \n \t# Clone. The client has deltabase_have but not deltabase_missing.\n \tgit -c protocol.version=2 clone --no-checkout \\\n-\t\t--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&\n+\t\t--filter=blob:none $HTTPD_URL/one_time_script/server repo &&\n \tgit -C repo hash-object -w -- \"$SERVER/have.txt\" &&\n \n \t# Sanity check to ensure that the client does not have\n@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against\n \tgrep \"want $(cat deltabase_missing)\" trace &&\n \t! grep \"want $(cat deltabase_have)\" trace &&\n \n-\t# Ensure that the one-time-perl script was used.\n-\t! test -e \"$HTTPD_ROOT_PATH/one-time-perl\"\n+\t# Ensure that the one-time-script script was used.\n+\t! test -e \"$HTTPD_ROOT_PATH/one-time-script\"\n '\n \n # DO NOT add non-httpd-specific tests here, because the last part of this\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex ad5e772cd72..8548854f32e 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '\n \t! grep \"git< version 2\" log\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM' '\n+test_expect_success 'when server sends \"ready\", expect DELIM' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends \"ready\", expect DELIM'\n \n \t# After \"ready\" in the acknowledgments section, pretend that a FLUSH\n \t# (0000) was sent instead of a DELIM (0001).\n-\tprintf \"\\$ready = 1 if /ready/; \\$ready && s/0001/0000/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/ready/{n;s/0001/0000/;}\" \"$1\"\n+\tEOF\n \n \ttest_must_fail git -C http_child -c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \ttest_grep \"expected packfile to be sent after .ready.\" err\n '\n \n-test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect FLUSH' '\n+test_expect_success 'when server does not send \"ready\", expect FLUSH' '\n \trm -rf \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" http_child log &&\n \n \tgit init \"$HTTPD_DOCUMENT_ROOT_PATH/http_parent\" &&\n@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send \"ready\", expect\n \n \t# After the acknowledgments section, pretend that a DELIM\n \t# (0001) was sent instead of a FLUSH (0000).\n-\tprintf \"\\$ack = 1 if /acknowledgments/; \\$ack && s/0000/0001/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"/acknowledgments/,//{s/0000/0001/;}\" \"$1\"\n+\tEOF\n \n \ttest_must_fail env GIT_TRACE_PACKET=\"$(pwd)/log\" git -C http_child \\\n \t\t-c protocol.version=2 \\\n-\t\tfetch \"$HTTPD_URL/one_time_perl/http_parent\" 2> err &&\n+\t\tfetch \"$HTTPD_URL/one_time_script/http_parent\" 2> err &&\n \tgrep \"fetch< .*acknowledgments\" log &&\n \t! grep \"fetch< .*ready\" log &&\n \ttest_grep \"expected no other sections to be sent after no .ready.\" err\n@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '\n \tgrep \"$COMMON\" out\n '\n \n-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '\n+test_expect_success 'http:// --negotiate-only without wait-for-done support' '\n \tSERVER=\"server\" &&\n-\tURI=\"$HTTPD_URL/one_time_perl/server\" &&\n+\tURI=\"$HTTPD_URL/one_time_script/server\" &&\n \n \tsetup_negotiate_only \"$SERVER\" \"$URI\" &&\n \n-\techo \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \\\n-\t\t>\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/ wait-for-done/ xxxx-xxx-xxxx/\" \"$1\"\n+\tEOF\n \n \ttest_must_fail git -c protocol.version=2 -C client fetch \\\n \t\t--no-tags \\\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex f59d47aa6c6..fc915e7b823 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '\n \t\ttest_commit m3 &&\n \t\tgit tag -d m2 m3\n \t) &&\n-\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo\" &&\n+\tgit -C \"$LOCAL_PRISTINE\" remote set-url origin \"http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo\" &&\n \tgit -C \"$LOCAL_PRISTINE\" config protocol.version 2\n '\n \n@@ -481,7 +481,9 @@ inconsistency () {\n \t# RPCs during a single negotiation.\n \toid1=$(git -C \"$REPO\" rev-parse $1) &&\n \toid2=$(git -C \"$REPO\" rev-parse $2) &&\n-\techo \"s/$oid1/$oid2/\" >\"$HTTPD_ROOT_PATH/one-time-perl\"\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-EOF\n+\tsed \"s/$oid1/$oid2/\" \"\\$1\"\n+\tEOF\n }\n \n test_expect_success 'server is initially ahead - no ref in want' '\n@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n-\techo \"s/main/rain/\" >\"$HTTPD_ROOT_PATH/one-time-perl\" &&\n+\twrite_script \"$HTTPD_ROOT_PATH/one-time-script\" <<-\\EOF &&\n+\tsed \"s/main/rain/\" \"$1\"\n+\tEOF\n \ttest_must_fail git -C local fetch 2>err &&\n \n \ttest_grep \"fatal: remote error: unknown ref refs/heads/rain\" err\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515563","messageId":"20250403-b4-pks-t-perlless-v4-18-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 18/20] t0210: refactor trace2 scrubbing to not use Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:09Z","receivedAt":"2025-04-03T05:06:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The output generated by our trace2 mechanism contains several fields\nthat are dependent on the environment they're being run in, which makes\nit somewhat harder to test it. As a countermeasure we scrub the output\nand strip out any fields that contain such information.\n\nThe logic to do so is implemented in Perl, but it can be trivially\nported to instead use sed(1). Refactor the code accordingly so that we\ncan drop the PERL_TEST_HELPERS prerequisite.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------\n t/t0210/scrub_normal.perl | 54 -----------------------------------------\n 2 files changed, 43 insertions(+), 72 deletions(-)\n\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex ba4c0442b85..96c68f65df2 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping trace2 tests; Perl not available'\n-\ttest_done\n-fi\n-\n # Turn off any inherited trace2 settings for this test.\n sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT\n sane_unset GIT_TRACE2_BRIEF\n@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF\n #\n # Implicit return from cmd_<verb> function propagates <code>.\n \n+scrub_normal () {\n+\t# Scrub the variable fields from the normal trace2 output to make\n+\t# testing easier:\n+\t#\n+\t#   1. Various messages include an elapsed time in the middle of the\n+\t#      message. Replace the time with a placeholder to simplify our\n+\t#      HEREDOC in the test script.\n+\t#\n+\t#   2. We expect:\n+\t#\n+\t#        start <argv0> [<argv1> [<argv2> [...]]]\n+\t#\n+\t#      where argv0 might be a relative or absolute path, with or\n+\t#      without quotes, and platform dependent. Replace argv0 with a\n+\t#      token for HEREDOC matching in the test script.\n+\t#\n+\t#   3. Likewise, the 'cmd_path' message breaks out argv[0].\n+\t#\n+\t#      This line is only emitted when RUNTIME_PREFIX is defined,\n+\t#      so just omit it for testing purposes.\n+\t#\n+\t#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's\n+\t#      sake, skip it when parsing normal.\n+\tsed \\\n+\t\t-e 's/elapsed:[0-9]*\\.[0-9][0-9]*\\([eE][-+]\\{0,1\\}[0-9][0-9]*\\)\\{0,1\\}/elapsed:_TIME_/g' \\\n+\t\t-e \"s/^start '[^']*' \\(.*\\)/start _EXE_ \\1/\" \\\n+\t\t-e 's/^start [^ ][^ ]* \\(.*\\)/start _EXE_ \\1/' \\\n+\t\t-e '/^cmd_path/d' \\\n+\t\t-e '/^cmd_ancestry/d'\n+}\n+\n test_expect_success 'normal stream, return code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '\n test_expect_success 'normal stream, return code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 001return 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 1\n@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '\n \ttest_when_finished \"rm -r traces actual expect\" &&\n \tmkdir traces &&\n \tGIT_TRACE2=\"$(pwd)/traces\" test-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <\"$(ls traces/*)\" >actual &&\n+\tscrub_normal <\"$(ls traces/*)\" >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '\n test_expect_success 'normal stream, exit code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 0\n@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '\n test_expect_success 'normal stream, exit code 1' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 002exit 1 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 002exit 1\n@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '\n test_expect_success 'normal stream, error event' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \tGIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 003error \"hello world\" \"this is a test\" &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 003error '\\''hello world'\\'' '\\''this is a test'\\''\n@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '\n test_expect_success 'BUG messages are written to trace2' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n \ttest_must_fail env GIT_TRACE2=\"$(pwd)/trace.normal\" test-tool trace2 007bug &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 007bug\n@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 008bug\n@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 009bug_BUG\n@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '\n \tsed \"s/^.*: //\" <err >actual &&\n \ttest_cmp expect actual &&\n \n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 010bug_BUG\n@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '\n \ttest_config_global trace2.normalBrief 1 &&\n \ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\n@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '\n \tmv \"$(pwd)/.gitconfig\" \"$(pwd)/real.gitconfig\" &&\n \ttest_config_global include.path \"$(pwd)/real.gitconfig\" &&\n \ttest-tool trace2 001return 0 &&\n-\tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n+\tscrub_normal <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n \t\tversion $V\n \t\tstart _EXE_ trace2 001return 0\ndiff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl\ndeleted file mode 100644\nindex 7cc4de392a0..00000000000\n--- a/t/t0210/scrub_normal.perl\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-#!/usr/bin/perl\n-#\n-# Scrub the variable fields from the normal trace2 output to\n-# make testing easier.\n-\n-use strict;\n-use warnings;\n-\n-my $float = '[0-9]*\\.[0-9]+([eE][-+]?[0-9]+)?';\n-\n-# This code assumes that the trace2 data was written with bare\n-# turned on (which omits the \"<clock> <file>:<line>\" prefix.\n-\n-while (<>) {\n-    # Various messages include an elapsed time in the middle\n-    # of the message.  Replace the time with a placeholder to\n-    # simplify our HEREDOC in the test script.\n-    s/elapsed:$float/elapsed:_TIME_/g;\n-\n-    my $line = $_;\n-\n-    # we expect:\n-    #    start <argv0> [<argv1> [<argv2> [...]]]\n-    #\n-    # where argv0 might be a relative or absolute path, with\n-    # or without quotes, and platform dependent.  Replace argv0\n-    # with a token for HEREDOC matching in the test script.\n-\n-    if ($line =~ m/^start/) {\n-\t$line =~ /^start\\s+(.*)/;\n-\tmy $argv = $1;\n-\t$argv =~ m/(\\'[^\\']*\\'|[^ ]+)\\s+(.*)/;\n-\tmy $argv_0 = $1;\n-\tmy $argv_rest = $2;\n-\n-\tprint \"start _EXE_ $argv_rest\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_path/) {\n-\t# Likewise, the 'cmd_path' message breaks out argv[0].\n-\t#\n-\t# This line is only emitted when RUNTIME_PREFIX is defined,\n-\t# so just omit it for testing purposes.\n-\t# print \"cmd_path _EXE_\\n\";\n-    }\n-    elsif ($line =~ m/^cmd_ancestry/) {\n-\t# 'cmd_ancestry' is not implemented everywhere, so for portability's\n-\t# sake, skip it when parsing normal.\n-\t#\n-\t# print \"$line\";\n-    }\n-    else {\n-\tprint \"$line\";\n-    }\n-}\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515564","messageId":"20250403-b4-pks-t-perlless-v4-19-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 19/20] t5316: refactor `max_chain()` to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:10Z","receivedAt":"2025-04-03T05:06:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `max_chain()` helper function is used to extract the maximum delta\nchain of a packfile as printed by git-index-pack(1). The script uses\nPerl to extract that data, but it can be trivially refactored to use\nawk(1) instead.\n\nRefactor the helper accordingly so that we can drop a couple of\nPERL_TEST_HELPERS prerequisites.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5316-pack-delta-depth.sh | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh\nindex cd947b5a5ef..defaa06d650 100755\n--- a/t/t5316-pack-delta-depth.sh\n+++ b/t/t5316-pack-delta-depth.sh\n@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '\n \n max_chain() {\n \tgit index-pack --verify-stat-only \"$1\" >output &&\n-\tperl -lne '\n-\t  BEGIN { $len = 0 }\n-\t  /chain length = (\\d+)/ and $len = $1;\n-\t  END { print $len }\n-\t' output\n+\tawk '\n+\t\tBEGIN { len=0 }\n+\t\t/chain length = [0-9]+:/{ len=$4 }\n+\t\tEND { print len }\n+\t' <output | tr -d ':'\n }\n \n # Note that this whole setup is pretty reliant on the current\n # packing heuristics. We double-check that our test case\n # actually produces a long chain. If it doesn't, it should be\n # adjusted (or scrapped if the heuristics have become too unreliable)\n-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n+test_expect_success 'packing produces a long delta' '\n \t# Use --window=0 to make sure we are seeing reused deltas,\n \t# not computing a new long chain.\n \tpack=$(git pack-objects --all --window=0 </dev/null pack) &&\n@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '\n+test_expect_success '--depth limits depth' '\n \tpack=$(git pack-objects --all --depth=5 </dev/null pack) &&\n \techo 5 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '\n+test_expect_success '--depth=0 disables deltas' '\n \tpack=$(git pack-objects --all --depth=0 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '\n+test_expect_success 'negative depth disables deltas' '\n \tpack=$(git pack-objects --all --depth=-1 </dev/null pack) &&\n \techo 0 >expect &&\n \tmax_chain pack-$pack.pack >actual &&\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515565","messageId":"20250403-b4-pks-t-perlless-v4-20-be20ac3db39a@pks.im","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"[PATCH v4 20/20] t5703: refactor test to not depend on Perl","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-04-03T05:06:11Z","receivedAt":"2025-04-03T05:06:16Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We use Perl due to two different reasons in t5703:\n\n  - To filter advertised capabilities.\n\n  - To set up a CGI script with HTTPD.\n\nRefactor the first category to use `test_grep` instead. Refactoring the\nsecond category would be a bit more involved, so instead we add the\nPERL_TEST_HELPERS prerequisite to those individual tests now.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------\n 1 file changed, 8 insertions(+), 17 deletions(-)\n\ndiff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh\nindex fc915e7b823..249137b4673 100755\n--- a/t/t5703-upload-pack-ref-in-want.sh\n+++ b/t/t5703-upload-pack-ref-in-want.sh\n@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'\n \n . ./test-lib.sh\n \n-if ! test_have_prereq PERL_TEST_HELPERS\n-then\n-\tskip_all='skipping upload-pack ref-in-want tests; Perl not available'\n-\ttest_done\n-fi\n-\n get_actual_refs () {\n \tsed -n -e '/wanted-refs/,/0001/{\n \t\t/wanted-refs/d\n@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '\n \n test_expect_success 'config controls ref-in-want advertisement' '\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant false &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_must_be_empty out.filter &&\n+\ttest_grep ! \"ref-in-want\" out &&\n \n \tgit config uploadpack.allowRefInWant true &&\n \ttest-tool serve-v2 --advertise-capabilities >out &&\n-\tperl -ne \"/ref-in-want/ and print\" out >out.filter &&\n-\ttest_file_not_empty out.filter\n+\ttest_grep \"ref-in-want\" out\n '\n \n test_expect_success 'invalid want-ref line' '\n@@ -486,7 +477,7 @@ inconsistency () {\n \tEOF\n }\n \n-test_expect_success 'server is initially ahead - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '\n \ttest_grep \"fatal: remote error: upload-pack: not our ref\" err\n '\n \n-test_expect_success 'server is initially ahead - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - no ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant false &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server is initially behind - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '\n \ttest_cmp expected actual\n '\n \n-test_expect_success 'server loses a ref - ref in want' '\n+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '\n \tgit -C \"$REPO\" config uploadpack.allowRefInWant true &&\n \trm -rf local &&\n \tcp -r \"$LOCAL_PRISTINE\" local &&\n\n-- \n2.49.0.604.gff1f9ca942.dirty\n\n"},{"id":"515581","messageId":"5e00e50f-e2c5-a633-28ee-684e5026e92e@gmx.de","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-0-be20ac3db39a@pks.im","subject":"Re: [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-04-03T12:12:48Z","receivedAt":"2025-04-03T12:12:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Thu, 3 Apr 2025, Patrick Steinhardt wrote:\n\n> Changes in v4:\n>   - Improve a couple of commit messages to better explain the changes.\n>   - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im\n\nLooks good to me, as well as the range-diff.\n\nThank you,\nJohannes\n"},{"id":"515813","messageId":"xmqq5xjf1oip.fsf@gitster.g","threadId":"63168","inReplyTo":"5e00e50f-e2c5-a633-28ee-684e5026e92e@gmx.de","subject":"Re: [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-08T00:32:30Z","receivedAt":"2025-04-08T00:32:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Patrick,\n>\n> On Thu, 3 Apr 2025, Patrick Steinhardt wrote:\n>\n>> Changes in v4:\n>>   - Improve a couple of commit messages to better explain the changes.\n>>   - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im\n>\n> Looks good to me, as well as the range-diff.\n\nThanks, both of you.  Will replace and queue.\nLet me mark the topic for 'next'.\n"},{"id":"520054","messageId":"aEiNBwUkjbo2QlFY@szeder.dev","threadId":"63168","inReplyTo":"20250403-b4-pks-t-perlless-v4-12-be20ac3db39a@pks.im","subject":"Re: [PATCH v4 12/20] t: refactor tests depending on Perl to print data","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2025-06-10T19:52:39Z","receivedAt":"2025-06-10T19:52:43Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, Apr 03, 2025 at 07:06:03AM +0200, Patrick Steinhardt wrote:\n> A bunch of tests rely on Perl to print data in various different ways.\n> These usages fall into the following categories:\n> \n>   - Print data conditionally by matching patterns. These usecases can be\n>     converted to use awk(1) rather easily.\n> \n>   - Print data repeatedly. These usecases can typically be converted to\n>     use a combination of `test-tool genzeros` and sed(1).\n> \n>   - Print data in reverse. These usecases can be converted to use\n>     awk(1) or `sort -r`.\n> \n> Refactor the tests accordingly so that we can drop a couple of\n> PERL_TEST_HELPERS prerequisites.\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n\n> diff --git a/t/t4150-am.sh b/t/t4150-am.sh\n> index 4794510d70d..2ae93d3c967 100755\n> --- a/t/t4150-am.sh\n> +++ b/t/t4150-am.sh\n> @@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n>  \ttest_cmp msg out\n>  '\n>  \n> -test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '\n> +test_expect_success 'am works with multi-line in-body headers' '\n>  \tFORTY=\"String that has a length of more than forty characters\" &&\n>  \tLONG=\"$FORTY $FORTY\" &&\n>  \trm -fr .git/rebase-apply &&\n> @@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'\n>      Body test\" --author=\"$LONG <long@example.com>\" &&\n>  \tgit format-patch --stdout -1 >patch &&\n>  \t# bump from, date, and subject down to in-body header\n> -\tperl -lpe \"\n> -\t\tif (/^From:/) {\n> +\tawk \"\n> +\t\t/^From:/{\n>  \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n>  \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n>  \t\t\tprint \\\"Subject: x\\n\\\";\n> -\t\t}\n> -\t\" patch >msg &&\n> +\t\t}; 1\n> +\t\" <patch >msg &&\n\nWith the conversion to awk I get the following warning from gawk:\n\n  awk: cmd. line:3: warning: escape sequence `\\@' treated as plain `@'\n\n>  \tgit checkout HEAD^ &&\n>  \tgit am msg &&\n>  \t# Ensure that the author and full message are present\n\n> diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh\n> index 1059ff45fe4..56674db562f 100755\n> --- a/t/t5333-pseudo-merge-bitmaps.sh\n> +++ b/t/t5333-pseudo-merge-bitmaps.sh\n> @@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0\n>  \n>  . ./test-lib.sh\n>  \n> -if ! test_have_prereq PERL_TEST_HELPERS\n> -then\n> -\tskip_all='skipping pseudo-merge bitmap tests; Perl not available'\n> -\ttest_done\n> -fi\n> -\n>  test_pseudo_merges () {\n>  \ttest-tool bitmap dump-pseudo-merges\n>  }\n> @@ -34,9 +28,8 @@ test_pseudo_merges_reused () {\n>  \n>  tag_everything () {\n>  \tgit rev-list --all --no-object-names >in &&\n> -\tperl -lne '\n> -\t\tprint \"create refs/tags/\" . $. . \" \" . $1 if /([0-9a-f]+)/\n> -\t' <in | git update-ref --stdin\n> +\tsed 's|\\(.*\\)|create refs/tags/\\1 \\1|' in |\n> +\tgit update-ref --stdin\n>  }\n>  \n>  test_expect_success 'setup' '\n> @@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> -test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n> +test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '\n>  \ttest_config bitmapPseudoMerge.test.pattern \"refs/tags/\" &&\n>  \ttest_config bitmapPseudoMerge.test.maxMerges 1 &&\n>  \ttest_config bitmapPseudoMerge.test.stableThreshold never &&\n> @@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n>  \t\t\ttest_commit_bulk 16 &&\n>  \n>  \t\t\tgit rev-list HEAD~16.. >in &&\n> -\n> -\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n> +\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n\nThis conversion results in the error:\n\n  sed: -e expression #1, char 41: unterminated `s' command\n\nI find it suspicious that the test still succeeds...\n\n>  \t\t\tgit update-ref --stdin || return 1\n>  \t\tdone &&\n>  \n> @@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n>  \t\tdo\n>  \t\t\ttest_pseudo_merge_commits $m >oids &&\n>  \t\t\tgrep -f oids refs |\n> -\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n> +\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n>  \t\t\tsort -u || return 1\n>  \t\tdone >remotes &&\n>  \n"},{"id":"520059","messageId":"xmqq5xh3mgg9.fsf@gitster.g","threadId":"63168","inReplyTo":"aEiNBwUkjbo2QlFY@szeder.dev","subject":"Re: [PATCH v4 12/20] t: refactor tests depending on Perl to print data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-06-10T21:31:34Z","receivedAt":"2025-06-10T21:31:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n>> -\tperl -lpe \"\n>> -\t\tif (/^From:/) {\n>> +\tawk \"\n>> +\t\t/^From:/{\n>>  \t\t\tprint \\\"From: x <x\\@example.com>\\\";\n>>  \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n>>  \t\t\tprint \\\"Subject: x\\n\\\";\n>> -\t\t}\n>> -\t\" patch >msg &&\n>> +\t\t}; 1\n>> +\t\" <patch >msg &&\n>\n> With the conversion to awk I get the following warning from gawk:\n>\n>   awk: cmd. line:3: warning: escape sequence `\\@' treated as plain `@'\n\nThanks for noticing.\n\nThe backslash protecting the array @example from getting referenced\ncan safely be removed, as \"@\" in string means nothing special here,\nunlike in the original in Perl.\n\n>> @@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n>>  \t\t\ttest_commit_bulk 16 &&\n>>  \n>>  \t\t\tgit rev-list HEAD~16.. >in &&\n>> -\n>> -\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n>> +\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n>\n> This conversion results in the error:\n>\n>   sed: -e expression #1, char 41: unterminated `s' command\n\nThis not just misses the terminating \"|\", but the conversion seems\nnot very faithful to the original.  It used to create tags 1 2 3 4\n5... but now the tags it tries to create (unsuccessfully) are the\nnames of tagged objects in full hexadecimal glory.\n\n> I find it suspicious that the test still succeeds...\n\nThat is because the downstream \"update-ref --stdin\" does not notice\nanything wrong in its input, which is empty.\n\n>>  \t\t\tgit update-ref --stdin || return 1\n>>  \t\tdone &&\n\nAnd the step after this, which is not touched by this patch, may not\nbe testing what it wants to test.  test_pseudo_merges produces no\nlines, and iterating over the lines in that file produces an empty\nresult in \"remotes\" below ...\n\n>> @@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n>>  \t\tdo\n>>  \t\t\ttest_pseudo_merge_commits $m >oids &&\n>>  \t\t\tgrep -f oids refs |\n>> -\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n>> +\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n>>  \t\t\tsort -u || return 1\n>>  \t\tdone >remotes &&\n\n... and then it checks remotes has no duplicated lines with\n\n\t\ttest $(wc -l <remotes) -eq $(sort -u <remotes | wc -l)\n\nNo wonder it passes, as remotes is an empty file ;-)\n\n"},{"id":"520060","messageId":"xmqqy0tzl1b1.fsf@gitster.g","threadId":"63168","inReplyTo":"aEiNBwUkjbo2QlFY@szeder.dev","subject":"Re: [PATCH v4 12/20] t: refactor tests depending on Perl to print data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-06-10T21:44:02Z","receivedAt":"2025-06-10T21:44:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\n---\n * I hear Patrick is ooo and this breakage might not be grave enough\n   for a hotfix.  But just in case...\n\n t/t4150-am.sh                   | 2 +-\n t/t5333-pseudo-merge-bitmaps.sh | 6 +++---\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git c/t/t4150-am.sh w/t/t4150-am.sh\nindex 2ae93d3c96..699a81ab5c 100755\n--- c/t/t4150-am.sh\n+++ w/t/t4150-am.sh\n@@ -1086,7 +1086,7 @@ test_expect_success 'am works with multi-line in-body headers' '\n \t# bump from, date, and subject down to in-body header\n \tawk \"\n \t\t/^From:/{\n-\t\t\tprint \\\"From: x <x\\@example.com>\\\";\n+\t\t\tprint \\\"From: x <x@example.com>\\\";\n \t\t\tprint \\\"Date: Sat, 1 Jan 2000 00:00:00 +0000\\\";\n \t\t\tprint \\\"Subject: x\\n\\\";\n \t\t}; 1\ndiff --git c/t/t5333-pseudo-merge-bitmaps.sh w/t/t5333-pseudo-merge-bitmaps.sh\nindex 56674db562..de0dc7c412 100755\n--- c/t/t5333-pseudo-merge-bitmaps.sh\n+++ w/t/t5333-pseudo-merge-bitmaps.sh\n@@ -221,7 +221,7 @@ test_expect_success 'out of order thresholds are rejected' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'pseudo-merge pattern with capture groups' '\n+test_expect_success PERL_TEST_HELPERS 'pseudo-merge pattern with capture groups' '\n \tgit init pseudo-merge-captures &&\n \t(\n \t\tcd pseudo-merge-captures &&\n@@ -234,7 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\t\ttest_commit_bulk 16 &&\n \n \t\t\tgit rev-list HEAD~16.. >in &&\n-\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n+\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n \t\t\tgit update-ref --stdin || return 1\n \t\tdone &&\n \n@@ -250,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n \t\tdo\n \t\t\ttest_pseudo_merge_commits $m >oids &&\n \t\t\tgrep -f oids refs |\n-\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n+\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n \t\t\tsort -u || return 1\n \t\tdone >remotes &&\n \n"},{"id":"521424","messageId":"aGuZFIWFA3J0VkDZ@pks.im","threadId":"63168","inReplyTo":"xmqq5xh3mgg9.fsf@gitster.g","subject":"Re: [PATCH v4 12/20] t: refactor tests depending on Perl to print data","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-07-07T09:53:24Z","receivedAt":"2025-07-07T09:53:31Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Jun 10, 2025 at 02:31:34PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder.dev@gmail.com> writes:\n> >> @@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n> >>  \t\t\ttest_commit_bulk 16 &&\n> >>  \n> >>  \t\t\tgit rev-list HEAD~16.. >in &&\n> >> -\n> >> -\t\t\tperl -lne \"print \\\"create refs/remotes/$r/tags/\\$. \\$_\\\"\" <in |\n> >> +\t\t\tsed \"s|\\(.*\\)|create refs/remotes/$r/tags/\\1 \\1\" in |\n> >\n> > This conversion results in the error:\n> >\n> >   sed: -e expression #1, char 41: unterminated `s' command\n> \n> This not just misses the terminating \"|\", but the conversion seems\n> not very faithful to the original.  It used to create tags 1 2 3 4\n> 5... but now the tags it tries to create (unsuccessfully) are the\n> names of tagged objects in full hexadecimal glory.\n\nYup, that change was intentional. Anything past \"refs/remotes/$r/tags\"\ndoesn't matter: the pseudo-merge patterns only match on\n\"refs/remotes/([0-9]+)/tags/\", so the final part of the tag name does\nnot matter. It was simply easier to slightly change the format than to\nfaithfully retain the original refnames.\n\n> > I find it suspicious that the test still succeeds...\n> \n> That is because the downstream \"update-ref --stdin\" does not notice\n> anything wrong in its input, which is empty.\n\nUgh, indeed.\n\n> >>  \t\t\tgit update-ref --stdin || return 1\n> >>  \t\tdone &&\n> \n> And the step after this, which is not touched by this patch, may not\n> be testing what it wants to test.  test_pseudo_merges produces no\n> lines, and iterating over the lines in that file produces an empty\n> result in \"remotes\" below ...\n\nYup. This is a consequence of us not having created the tags though. The\npseudo-merge patterns we have configured don't match anything, and\nbecause of that the test doesn't do anything.\n\n> >> @@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '\n> >>  \t\tdo\n> >>  \t\t\ttest_pseudo_merge_commits $m >oids &&\n> >>  \t\t\tgrep -f oids refs |\n> >> -\t\t\tperl -lne \"print \\$1 if /refs\\/remotes\\/([0-9]+)/\" |\n> >> +\t\t\tsed -n \"s|refs/remotes/\\([0-9][0-9]*\\)/|\\1|p\" &&\n> >>  \t\t\tsort -u || return 1\n> >>  \t\tdone >remotes &&\n> \n> ... and then it checks remotes has no duplicated lines with\n> \n> \t\ttest $(wc -l <remotes) -eq $(sort -u <remotes | wc -l)\n> \n> No wonder it passes, as remotes is an empty file ;-)\n\nTrue.\n\nBut in any case, the test does what it's intended to do again if we\nappend the missing \"|\" terminator.\n\nI'll send a patch in a bit, thanks!\n\nPatrick\n"}]}