Git Mailing List Archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/20] t: drop Perl as a mandatory prerequisite
@ 2025-03-20  9:35 Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
                   ` (22 more replies)
  0 siblings, 23 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

Hi,

while Git was initially building on Perl quite a lot, the significance
of Perl has been dwindling over the years as more and more functionality
was converted into C builtins. Nowadays, an installation with Perl-based
features disabled is almost fully functional, only a handful of features
remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these features really are critical for day-to-day usage of Git,
and most users probably wouldn't even notice if those features were not
installed. Perl is thus very much optional nowadays.

There is one big exception though: it is impossible to run our test
suite without a Perl interpreter, so it is not easily possible to verify
that a Perl-less installation actually works as expected. For most of
the part though our test suite doesn't use all that much Perl, either.
It is present in a couple of critical paths, but those are easy to adapt
to not use Perl anymore.

This is exactly what this patch series does: it refactors a couple of
central parts in our test suite to not use Perl anymore so that it
becomes possible to run most of our tests entirely without Perl. Tests
that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq
so that they only execute when a Perl interpreter is available.

With this patch series, 30342 out of 31358 tests pass, which is around
97% of our tests.

Thanks!

Patrick

---
Patrick Steinhardt (20):
      t: skip chain lint when PERL_PATH is unset
      t: refactor environment sanitization to not use Perl
      t: adapt character translation helpers to not use Perl
      t: adapt `test_copy_bytes()` to not use Perl
      t: adapt `test_readlink()` to not use Perl
      t: introduce PERL_TEST_HELPERS prerequisite
      t: adapt existing PERL prerequisites
      meson: stop requiring Perl when tests are enabled
      Makefile: stop requiring Perl when running tests
      t: refactor tests depending on Perl transliteration operator
      t: refactor tests depending on Perl substitution operator
      t: refactor tests depending on Perl to print data
      t: refactor tests depending on Perl for textconv scripts
      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
      t/lib-t6000: refactor `name_from_description()` to not depend on Perl
      t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
      t0021: refactor `generate_random_characters()` to not depend on Perl
      t0210: refactor trace2 scrubbing to not use Perl
      t5316: refactor `max_chain()` to not depend on Perl
      t5703: refactor test to not depend on Perl

 meson.build                               |  2 +-
 t/Makefile                                | 16 +++++++--
 t/helper/test-path-utils.c                | 13 ++++++++
 t/helper/test-sha1.sh                     |  4 +--
 t/lib-diff.sh                             |  4 +--
 t/lib-gpg.sh                              |  6 +---
 t/lib-httpd.sh                            |  2 +-
 t/lib-httpd/apache.conf                   |  6 ++--
 t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------
 t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++
 t/lib-t6000.sh                            | 13 ++++----
 t/t0008-ignores.sh                        |  4 +--
 t/t0021-conversion.sh                     | 13 ++++----
 t/t0090-cache-tree.sh                     |  4 +--
 t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------
 t/t0210/scrub_normal.perl                 | 54 ------------------------------
 t/t0211-trace2-perf.sh                    |  6 ++++
 t/t0610-reftable-basics.sh                |  5 ++-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       | 16 +++++----
 t/t1007-hash-object.sh                    |  6 ++--
 t/t1010-mktree.sh                         |  4 +--
 t/t1450-fsck.sh                           |  6 ++--
 t/t3300-funny-names.sh                    |  6 ++--
 t/t4013-diff-various.sh                   |  6 ++++
 t/t4014-format-patch.sh                   | 30 ++++++++---------
 t/t4020-diff-external.sh                  |  2 +-
 t/t4029-diff-trailing-space.sh            |  3 +-
 t/t4030-diff-textconv.sh                  |  9 ++---
 t/t4031-diff-rewrite-binary.sh            | 17 ++++------
 t/t4058-diff-duplicates.sh                |  6 ++++
 t/t4103-apply-binary.sh                   |  6 ++--
 t/t4116-apply-reverse.sh                  |  4 +--
 t/t4150-am.sh                             |  8 ++---
 t/t4200-rerere.sh                         |  8 ++---
 t/t4205-log-pretty-formats.sh             |  6 ++--
 t/t4216-log-bloom.sh                      |  8 ++---
 t/t5004-archive-corner-cases.sh           |  6 ++++
 t/t5300-pack-object.sh                    | 10 +++---
 t/t5303-pack-corruption-resilience.sh     |  6 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               | 10 +++---
 t/t5318-commit-graph.sh                   | 12 +++----
 t/t5319-multi-pack-index.sh               | 16 ++++-----
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  4 +--
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  2 +-
 t/t5503-tagfollow.sh                      |  6 ++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++
 t/t5532-fetch-proxy.sh                    |  6 ++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  | 15 ++++-----
 t/t5551-http-fetch-smart.sh               |  7 ++++
 t/t5562-http-backend-content-length.sh    |  6 ++++
 t/t5601-clone.sh                          |  4 +--
 t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------
 t/t5701-git-serve.sh                      |  5 ++-
 t/t5702-protocol-v2.sh                    | 21 +++++++-----
 t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------
 t/t5710-promisor-remote-capability.sh     |  6 ++++
 t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---
 t/t6013-rev-list-reverse-parents.sh       | 10 +++---
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++
 t/t6115-rev-list-du.sh                    |  2 +-
 t/t6300-for-each-ref.sh                   | 15 ++++++---
 t/t7006-pager.sh                          |  6 ++--
 t/t7416-submodule-dash-url.sh             |  3 +-
 t/t7501-commit-basic-functionality.sh     |  6 ++--
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  9 ++---
 t/t8001-annotate.sh                       |  6 ++++
 t/t8002-blame.sh                          |  8 ++++-
 t/t8006-blame-textconv.sh                 |  2 +-
 t/t8011-blame-split-file.sh               |  6 ++--
 t/t8012-blame-colors.sh                   |  6 ++++
 t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib-functions.sh                   | 20 +++--------
 t/test-lib.sh                             | 49 +++++++++++++++++----------
 84 files changed, 471 insertions(+), 373 deletions(-)


---
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
change-id: 20250317-b4-pks-t-perlless-138cf94696b8


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH 01/20] t: skip chain lint when PERL_PATH is unset
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20 18:36   ` Eric Sunshine
  2025-03-20  9:35 ` [PATCH 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

Our chainlint scripts verify that test files have proper '&&' chains.
These scripts are written in Perl and are executed for every test file
before executing the test logic itself.

In subsequent commits we're about to refactor our test suite so that
Perl becomes an optional dependency, only. And while it is already
possible to disable this linter, developers that don't have Perl
available at all would always have to disable the linter manually, which
is rather cumbersome.

Disable the chain linter automatically in case PERL_PATH isn't set to
make this a bit less annoying. Bail out with an error in case the
developer has asked explicitly for the chain linter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9001ed3a647..1ce3b32fcac 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1523,6 +1523,22 @@ then
 	export LSAN_OPTIONS
 fi
 
+if test -z "$PERL_PATH"
+then
+	case "${GIT_TEST_CHAIN_LINT:-unset}" in
+	unset)
+		GIT_TEST_CHAIN_LINT=0
+		;;
+	0)
+		# The user has explicitly disabled the chain linter, so we
+		# don't have anything to worry about.
+		;;
+	*)
+		BAIL_OUT 'You need Perl for the chain linter'
+		;;
+	esac
+fi
+
 if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
    test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 02/20] t: refactor environment sanitization to not use Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-21  9:52   ` Karthik Nayak
  2025-03-20  9:35 ` [PATCH 03/20] t: adapt character translation helpers " Patrick Steinhardt
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

Before executing tests we first sanitize the environment. Part of the
sanitization is to unset a couple of environment variables that we know
will change the behaviour of Git. This is done with a small Perl script,
which has the consequence that having a Perl interpreter available is a
strict requirement for running our unit tests.

The logic itself isn't particularly involved: we simply unset every
environment variable whose key starts with 'GIT_', but then explicitly
allow a subset of these.

Refactor the logic to instead use sed(1) so that it becomes possible to
execute our tests without Perl.

Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1ce3b32fcac..a62699d6c79 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -499,24 +499,20 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
-	my @env = keys %ENV;
-	my $ok = join("|", qw(
-		TRACE
-		DEBUG
-		TEST
-		.*_TEST
-		PROVE
-		VALGRIND
-		UNZIP
-		PERF_
-		CURL_VERBOSE
-		TRACE_CURL
-		BUILD_DIR
-	));
-	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
-	print join("\n", @vars);
-')
+unset VISUAL EMAIL LANGUAGE $(env | sed -n \
+	-e '/^GIT_TRACE/d' \
+	-e '/^GIT_DEBUG/d' \
+	-e '/^GIT_TEST/d' \
+	-e '/^GIT_.*_TEST/d' \
+	-e '/^GIT_PROVE/d' \
+	-e '/^GIT_VALGRIND/d' \
+	-e '/^GIT_UNZIP/d' \
+	-e '/^GIT_PERF_/d' \
+	-e '/^GIT_CURL_VERBOSE/d' \
+	-e '/^GIT_TRACE_CURL/d' \
+	-e '/^GIT_BUILD_DIR/d' \
+	-e 's/^\(GIT_[^=]*\)=.*/\1/p'
+)
 unset XDG_CACHE_HOME
 unset XDG_CONFIG_HOME
 unset GITPERLLIB

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 03/20] t: adapt character translation helpers to not use Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

We have a couple of helper functions that translate characters, e.g.
from LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl
scripts, but they can be trivially adapted to instead use tr(1).

Note that one specialty here is the handling of NUL characters in tr(1),
which historically wasn't implemented correctly on all platforms. But
quoting tr(1p):

    It was considered that automatically stripping NUL characters from
    the input was not correct functionality.  However, the removal of -n
    in a later proposal does not remove the requirement that tr
    correctly process NUL characters in its input stream.

So when tr(1) is implemented following the POSIX standard then it is
expected to handle the transliteration of NUL just fine.

Refactor the helpers accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 79377bc0fc2..377f08a1428 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -88,15 +88,15 @@ test_decode_color () {
 }
 
 lf_to_nul () {
-	perl -pe 'y/\012/\000/'
+	tr '\012' '\000'
 }
 
 nul_to_q () {
-	perl -pe 'y/\000/Q/'
+	tr '\000' 'Q'
 }
 
 q_to_nul () {
-	perl -pe 'y/Q/\000/'
+	tr 'Q' '\000'
 }
 
 q_to_cr () {

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 04/20] t: adapt `test_copy_bytes()` to not use Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (2 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 03/20] t: adapt character translation helpers " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-21  9:56   ` Karthik Nayak
  2025-03-20  9:35 ` [PATCH 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `test_copy_bytes()` helper function copies up to N bytes from stdin
to stdout. This is implemented using Perl, but it can be trivially
adapted to instead use dd(1).

Refactor the helper accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 377f08a1428..c4b4d3a4c7f 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1640,17 +1640,7 @@ test_match_signal () {
 
 # Read up to "$1" bytes (or to EOF) from stdin and write them to stdout.
 test_copy_bytes () {
-	perl -e '
-		my $len = $ARGV[1];
-		while ($len > 0) {
-			my $s;
-			my $nread = sysread(STDIN, $s, $len);
-			die "cannot read: $!" unless defined($nread);
-			last unless $nread;
-			print $s;
-			$len -= $nread;
-		}
-	' - "$1"
+	dd ibs=1 count="$1" 2>/dev/null
 }
 
 # run "$@" inside a non-git directory

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 05/20] t: adapt `test_readlink()` to not use Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (3 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `test_readlink()` helper function reads a symbolic link and returns
the path it is pointing to. It is thus equivalent to the readlink(1)
utility, which isn't available on all supported platforms. As such, it
is implemented using Perl so that we can use it even on platforms where
the shell utility isn't available.

While using readlink(1) is not an option, what we can do is to implement
the logic ourselves in our test-tool. Do so, which allows a bunch of
tests to pass when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-path-utils.c | 13 +++++++++++++
 t/test-lib-functions.sh    |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 72ac8d1b1b0..54d9ba98c0e 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)
 		return 0;
 	}
 
+	if (argc >= 2 && !strcmp(argv[1], "readlink")) {
+		struct strbuf target = STRBUF_INIT;
+		while (argc > 2) {
+			if (strbuf_readlink(&target, argv[2], 0) < 0)
+				die_errno("cannot read link at '%s'", argv[2]);
+			puts(target.buf);
+			argc--;
+			argv++;
+		}
+		strbuf_release(&target);
+		return 0;
+	}
+
 	if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
 		while (argc > 2) {
 			puts(absolute_path(argv[2]));
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c4b4d3a4c7f..bff8c4d1b41 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1979,7 +1979,7 @@ test_remote_https_urls() {
 # Print the destination of symlink(s) provided as arguments. Basically
 # the same as the readlink command, but it's not available everywhere.
 test_readlink () {
-	perl -le 'print readlink($_) for @ARGV' "$@"
+	test-tool path-utils readlink "$@"
 }
 
 # Set mtime to a fixed "magic" timestamp in mid February 2009, before we

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (4 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20 18:55   ` Eric Sunshine
  2025-03-20  9:35 ` [PATCH 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

In the early days of Git, Perl was used quite prominently throughout the
project. This has changed significantly as almost all of the executables
we ship nowadays have eventually been rewritten in C. Only a handful of
subsystems remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these subsystems can really be considered to be part of the
"core" of Git, and an installation without them is fully functional.
It is more likely than not that an end user wouldn't even notice that
any features are missing if those tools weren't installed. But while
Perl nowadays very much is an optional dependency of Git, there is a
significant limitation when Perl isn't available: developers cannot run
our test suite.

Preceding commits have started to lift this restriction by removing the
strict dependency on Perl in many central parts of the test library. But
there are still many tests that rely on small Perl helpers to do various
different things.

Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
that require Perl. This prerequisite is explicitly different than the
preexisting PERL prerequisite:

  - PERL records whether or not features depending on the Perl
    interpreter are built.

  - PERL_TEST_HELPERS records whether or not a Perl interpreter is
    available for our tests.

By having these two separate prerequisites we can thus distinguish
between tests that inherently depend on Perl because the underlying
feature does, and those tests that depend on Perl because the test
itself is using Perl.

Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        |  6 ++++++
 t/t0021-conversion.sh                     |  4 ++--
 t/t0210-trace2-normal.sh                  |  6 ++++++
 t/t0211-trace2-perf.sh                    |  6 ++++++
 t/t0610-reftable-basics.sh                |  2 +-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       |  2 +-
 t/t1007-hash-object.sh                    |  6 +++---
 t/t1010-mktree.sh                         |  4 ++--
 t/t1450-fsck.sh                           |  6 +++---
 t/t3300-funny-names.sh                    |  6 +++---
 t/t4013-diff-various.sh                   |  6 ++++++
 t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------
 t/t4020-diff-external.sh                  |  4 ++--
 t/t4029-diff-trailing-space.sh            |  2 +-
 t/t4030-diff-textconv.sh                  |  6 ++++++
 t/t4031-diff-rewrite-binary.sh            |  2 +-
 t/t4058-diff-duplicates.sh                |  6 ++++++
 t/t4103-apply-binary.sh                   |  6 ++++++
 t/t4116-apply-reverse.sh                  |  6 ++++++
 t/t4150-am.sh                             |  2 +-
 t/t4200-rerere.sh                         |  6 ++++++
 t/t4205-log-pretty-formats.sh             |  6 +++---
 t/t4216-log-bloom.sh                      |  8 ++++----
 t/t5004-archive-corner-cases.sh           |  6 ++++++
 t/t5300-pack-object.sh                    |  6 ++++++
 t/t5303-pack-corruption-resilience.sh     |  4 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               |  8 ++++----
 t/t5318-commit-graph.sh                   | 12 ++++++------
 t/t5319-multi-pack-index.sh               | 16 ++++++++--------
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  2 +-
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  4 ++--
 t/t5503-tagfollow.sh                      |  6 ++++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++++
 t/t5532-fetch-proxy.sh                    |  6 ++++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  |  2 +-
 t/t5551-http-fetch-smart.sh               |  7 +++++++
 t/t5562-http-backend-content-length.sh    |  6 ++++++
 t/t5601-clone.sh                          |  4 ++--
 t/t5616-partial-clone.sh                  |  6 +++---
 t/t5701-git-serve.sh                      |  2 +-
 t/t5702-protocol-v2.sh                    |  6 +++---
 t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++
 t/t5710-promisor-remote-capability.sh     |  6 ++++++
 t/t6002-rev-list-bisect.sh                |  6 ++++++
 t/t6003-rev-list-topo-order.sh            |  6 ++++++
 t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++
 t/t6013-rev-list-reverse-parents.sh       |  4 ++--
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++
 t/t6115-rev-list-du.sh                    |  6 ++++++
 t/t6300-for-each-ref.sh                   |  6 ++++++
 t/t7006-pager.sh                          |  2 +-
 t/t7416-submodule-dash-url.sh             |  6 ++++++
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  6 ++++++
 t/t8001-annotate.sh                       |  6 ++++++
 t/t8002-blame.sh                          |  6 ++++++
 t/t8006-blame-textconv.sh                 |  6 ++++++
 t/t8011-blame-split-file.sh               |  6 +++---
 t/t8012-blame-colors.sh                   |  6 ++++++
 t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib.sh                             |  1 +
 71 files changed, 281 insertions(+), 93 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index c9376dffb58..1aaa6bf5ae8 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,6 +5,12 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping ignores tests; Perl not available'
+	test_done
+fi
+
 init_vars () {
 	global_excludes="global-excludes"
 }
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 3f6433d3045..9c3738ebb3f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success 'required process filter should process multiple packets' '
+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '
 	)
 '
 
-test_expect_success 'required process filter with clean error should fail' '
+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index 4287ed3fbb3..ba4c0442b85 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index bac90465406..760cf69087f 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_PERF_BRIEF
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 4618ffc108e..5e0a1fa176d 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success 'basic: can write large commit message' '
+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	perl -e "
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index e2708e11d5b..fa1e2f9eef8 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success 'small block size fails with large reflog message' '
+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 398865d6ebe..a574da3df53 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1270,7 +1270,7 @@ extract_batch_output () {
     ' "$@"
 }
 
-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '
 	git cat-file --batch-all-objects --batch >actual.raw &&
 	extract_batch_output $orig <actual.raw >actual &&
 	{
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index a0481139de5..b3cf53ff8c9 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '
 	grep "too-short tree object" err
 '
 
-test_expect_success 'malformed mode in tree' '
+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "9100644 \0$bin_oid" >tree-with-malformed-mode &&
@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '
 	grep "malformed mode in tree entry" err
 '
 
-test_expect_success 'empty filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "100644 \0$bin_oid" >tree-with-empty-filename &&
@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '
 	grep "empty filename in tree entry" err
 '
 
-test_expect_success 'duplicate filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	{
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index c291a2b33d7..4977998e205 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
 	perl -e "print reverse <>" <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
 	perl -e "print reverse <>" <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1142d..01050453762 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '
 	test_grep ! "fatal: empty filename in tree entry" out
 '
 
-test_expect_success 'tree entry with type mismatch' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	test_when_finished "remove_object \$commit" &&
@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '
 	test_grep ! "dangling blob" out
 '
 
-test_expect_success 'tree entry with bogus mode' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	blob=$(echo blob | git hash-object -w --stdin) &&
@@ -984,7 +984,7 @@ corrupt_index_checksum () {
 
 # Corrupt the checksum on the index and then
 # verify that only fsck notices.
-test_expect_success 'detect corrupt index file in fsck' '
+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '
 	cp .git/index .git/index.backup &&
 	test_when_finished "mv .git/index.backup .git/index" &&
 	corrupt_index_checksum &&
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index f5bf16abcd8..502b1572059 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'ls-files -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-index -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-tree -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68dbc0..782d97fb7df 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff various tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83fb8a4..2782b1fc183 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF
 ---
 EOF
 
-test_expect_success 'no threading' '
+test_expect_success PERL_TEST_HELPERS 'no threading' '
 	git checkout side &&
 	check_threading expect.no-threading main
 '
@@ -466,11 +466,11 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread' '
+test_expect_success PERL_TEST_HELPERS 'thread' '
 	check_threading expect.thread --thread main
 '
 
-test_expect_success '--thread overrides format.thread=deep' '
+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
@@ -490,7 +490,7 @@ In-Reply-To: <1>
 References: <1>
 EOF
 
-test_expect_success 'thread in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '
 	check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 		--thread main
 '
@@ -512,7 +512,7 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '
 	check_threading expect.cover-letter --cover-letter --thread main
 '
 
@@ -538,12 +538,12 @@ References: <1>
 	<0>
 EOF
 
-test_expect_success 'thread cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread main
 '
 
-test_expect_success 'thread explicit shallow' '
+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=shallow main
 '
@@ -562,7 +562,7 @@ References: <0>
 	<1>
 EOF
 
-test_expect_success 'thread deep' '
+test_expect_success PERL_TEST_HELPERS 'thread deep' '
 	check_threading expect.deep --thread=deep main
 '
 
@@ -584,7 +584,7 @@ References: <1>
 	<2>
 EOF
 
-test_expect_success 'thread deep in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '
 	check_threading expect.deep-irt  --thread=deep \
 		--in-reply-to="<test.message>" main
 '
@@ -609,7 +609,7 @@ References: <0>
 	<2>
 EOF
 
-test_expect_success 'thread deep cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '
 	check_threading expect.deep-cl --cover-letter --thread=deep main
 '
 
@@ -638,27 +638,27 @@ References: <1>
 	<3>
 EOF
 
-test_expect_success 'thread deep cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '
 	check_threading expect.deep-cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=deep main
 '
 
-test_expect_success 'thread via config' '
+test_expect_success PERL_TEST_HELPERS 'thread via config' '
 	test_config format.thread true &&
 	check_threading expect.thread main
 '
 
-test_expect_success 'thread deep via config' '
+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '
 	test_config format.thread deep &&
 	check_threading expect.deep main
 '
 
-test_expect_success 'thread config + override' '
+test_expect_success PERL_TEST_HELPERS 'thread config + override' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
 
-test_expect_success 'thread config + --no-thread' '
+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '
 	test_config format.thread deep &&
 	check_threading expect.no-threading --no-thread main
 '
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index f1efe482a59..189294de7ef 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet
 
 echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
 
-test_expect_success 'force diff with "diff"' '
+test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success 'diff --cached' '
+test_expect_success PERL_TEST_HELPERS 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index 32b6e9a4e76..a92a42990b1 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success "$test_description" '
+test_expect_success PERL_TEST_HELPERS "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index daebf9796f5..c7d8eb12453 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff textconv tests; Perl not available'
+	test_done
+fi
+
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index c4394a27b56..cbe50b15772 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success 'rewrite diff respects textconv' '
+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
 	git diff -B >diff &&
 	grep "dissimilarity index" diff &&
 	grep "^-61" diff &&
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2fce4a98977..16266dff2af 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff duplicates tests; Perl not available'
+	test_done
+fi
+
 # make_tree_entry <mode> <mode> <sha1>
 #
 # We have to rely on perl here because not all printfs understand
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index d370ecfe0d9..4894605db7a 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping ignores tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 0784ba033a4..6f414ad27f5 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,6 +10,12 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply reverse tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c80eae..4794510d70d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success 'am works with multi-line in-body headers' '
+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b0a3e849841..50fe8b0fd05 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rerere tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f81e42a84d5..8f2ba98963f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trail
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:unfold) unfolds trailers' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '
 	git log --no-walk --pretty="%(trailers:unfold)" >actual &&
 	{
 		unfold <trailers &&
@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '
 	test_cmp expect actual
 '
 
-test_expect_success ':only and :unfold work together' '
+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '
 	git log --no-walk --pretty="%(trailers:only,unfold)" >actual &&
 	git log --no-walk --pretty="%(trailers:unfold,only)" >reverse &&
 	test_cmp actual reverse &&
@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '
 	git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual &&
 	unfold <trailers | grep Signed-off-by >expect &&
 	test_cmp expect actual
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 3f163dc3969..8910d53cac1 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -738,20 +738,20 @@ check_corrupt_graph () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'Bloom reader notices too-small data chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
 	check_corrupt_graph BDAT clear 00000000 &&
 	echo "warning: ignoring too-small changed-path chunk" \
 		"(4 < 12) in commit-graph file" >expect.err &&
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
 	check_corrupt_graph BIDX 12 FFFFFFFF &&
 	# use grep to avoid depending on exact chunk size
 	grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
 '
 
-test_expect_success 'Bloom reader notices too-small index chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
 	# replace the index with a single entry, making most
 	# lookups out-of-bounds
 	check_corrupt_graph BIDX clear 00000000 &&
@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-order index offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
 	# we do not know any real offsets, but we can pick
 	# something plausible; we should not get to the point of
 	# actually reading from the bogus offsets anyway.
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 50344e17ca1..51749951916 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping archive corner cases tests; Perl not available'
+	test_done
+fi
+
 # the 10knuls.tar file is used to test for an empty git generated tar
 # without having to invoke tar because an otherwise valid empty GNU tar
 # will be considered broken by {Open,Net}BSD tar
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 5ac8d39094b..143856c29f1 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,6 +7,12 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pack-object tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	rm -f .git/index* &&
 	perl -e "print \"a\" x 4096;" >a &&
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index de58ca654a1..ac5e370e1e4 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first object' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
@@ -156,7 +156,7 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first delta' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 621bbbdd26e..81987296235 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 32cf4227451..cd947b5a5ef 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -87,7 +87,7 @@ max_chain() {
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success 'packing produces a long delta' '
+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success '--depth limits depth' '
+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success '--depth=0 disables deltas' '
+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success 'negative depth disables deltas' '
+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index f68f64cd85e..0b3404f58fe 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -837,7 +837,7 @@ check_corrupt_chunk () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	# make it big enough that the graph file is plausible,
 	# otherwise we hit an earlier check
 	check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices fanout/lookup table mismatch' '
+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '
 	check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph OID lookup chunk is the wrong size
@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# Rather than try to corrupt a specific hash, we will just
 	# wreck them all. But we cannot just set them all to 0xFFFFFFFF or
 	# similar, as they are used for hi/lo starts in a binary search (so if
@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small commit data chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '
 	check_corrupt_chunk CDAT clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph commit data chunk is wrong size
@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds extra edge' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '
 	check_corrupt_chunk EDGE clear &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph extra-edges pointer out of bounds
@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small generations chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '
 	check_corrupt_chunk GDA2 clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph generations chunk is wrong size
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 0f215ad2e88..bd75dea9501 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1120,7 +1120,7 @@ corrupt_chunk () {
 	corrupt_chunk_file $midx "$@"
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	corrupt_chunk OIDF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small oid lookup chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '
 	corrupt_chunk OIDL clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small pack names chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '
 	# There is no NUL to terminate the name here, so the
 	# chunk is too short.
 	corrupt_chunk PNAM clear 70656666 &&
@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader handles unaligned chunks' '
+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '
 	# A 9-byte PNAM means all of the subsequent chunks
 	# will no longer be 4-byte aligned, but it is still
 	# a valid one-pack chunk on its own (it is "foo.pack\0").
@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small object offset chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '
 	corrupt_chunk OOFF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader bounds-checks large offset table' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '
 	# re-use the objects64 dir here to cheaply get access to a midx
 	# with large offsets.
 	git init repo &&
@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '
 	)
 '
 
-test_expect_success 'reader notices too-small revindex chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '
 	# We only get a revindex with bitmaps (and likewise only
 	# load it when they are asked for).
 	test_config repack.writeBitmaps true &&
@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# This is similar to the out-of-bounds fanout test in t5318. The values
 	# in adjacent entries should be large but not identical (they
 	# are used as hi/lo starts for a binary search, which would then abort
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index a32be3867df..49a057cc2eb 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '
 	)
 '
 
-test_expect_success 'reader bounds-checks base-graph chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '
 	git clone --no-hardlinks . corrupt-base-chunk &&
 	(
 		cd corrupt-base-chunk &&
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index d27557b9b04..627f8b4efdc 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index a766a3e3f84..d8891e6a922 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
 	git -C repo-uint32-max commit-graph verify
 '
 
-test_expect_success 'reader notices out-of-bounds generation overflow' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '
 	graph=.git/objects/info/commit-graph &&
 	test_when_finished "rm -rf $graph" &&
 	git commit-graph write --reachable &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 3905cb6e4f1..1059ff45fe4 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
+	test_done
+fi
+
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16e133..571e8f1bc59 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -268,7 +268,7 @@ extract_ref_advertisement () {
 	'
 }
 
-test_expect_success 'receive-pack de-dupes .have lines' '
+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '
 	git init shared &&
 	git -C shared commit --allow-empty -m both &&
 	git clone -s shared fork &&
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 0b28e4e452f..6a009fdcd71 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -20,7 +20,7 @@ extract_haves () {
 	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
 }
 
-test_expect_success 'with core.alternateRefsCommand' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success 'with core.alternateRefsPrefixes' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 845ca43ea0a..febe4410417 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping tagfollow tests; Perl not available'
+	test_done
+fi
+
 # End state of the repository:
 #
 #         T - tag1          S - tag2
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 58074506c59..438250c75ed 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -359,7 +359,7 @@ test_expect_success \
 	grep "Cannot demote unterminatedheader" act
 '
 
-test_expect_success 'badFilemode is not a strict error' '
+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '
 	git init --bare badmode.git &&
 	tree=$(
 		cd badmode.git &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 5f350facf5e..432a2264e6f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -8,6 +8,12 @@ test_description='Per branch config variables affects "git fetch".
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch tests; Perl not available'
+	test_done
+fi
+
 D=$(pwd)
 
 test_expect_success setup '
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
index 37558226290..95d0f33b295 100755
--- a/t/t5532-fetch-proxy.sh
+++ b/t/t5532-fetch-proxy.sh
@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch proxy tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup remote repo' '
 	git init remote &&
 	(cd remote &&
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index c91a62b77af..342d0423c92 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 37f7547a4ca..77d20d19110 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 761fdfcfe6c..b0d4ea78015 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
+
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http fetch smart tests; Perl not available'
+	test_done
+fi
+
 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
 start_httpd
 
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index f3b158274c4..b6ee06f5c8f 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http backend content tests; Perl not available'
+	test_done
+fi
+
 test_lazy_prereq GZIP 'gzip --version'
 
 verify_http_result() {
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d0c18660e33..d743d986c40 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
 	git -C replay.git index-pack -v --stdin <tmp.pack
 '
 
-test_expect_success 'clone on case-insensitive fs' '
+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '
 	git init icasefs &&
 	(
 		cd icasefs &&
@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '
 	)
 '
 
-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '
 	grep X icasefs/warning &&
 	grep x icasefs/warning &&
 	test_grep "the following paths have collided" icasefs/warning
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 46504519643..bc7e0fec8dc 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -751,7 +751,7 @@ replace_packfile () {
 	}' >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
-test_expect_success 'upon cloning, check that all refs point to objects' '
+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 678a346ed06..200bf06ecb3 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success 'ignore very large set of prefixes' '
+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index d3df81e7852..ad5e772cd72 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success 'when server sends "ready", expect DELIM' '
+test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends "ready", expect DELIM' '
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success 'when server does not send "ready", expect FLUSH' '
+test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
 	URI="$HTTPD_URL/one_time_perl/server" &&
 
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 191097171bc..f59d47aa6c6 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
+	test_done
+fi
+
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index d2cc69a17e4..9a420cf5605 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping promisor remote capabilities tests; Perl not available'
+	test_done
+fi
+
 GIT_TEST_MULTI_PACK_INDEX=0
 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index daa009c9a1b..5e1482aff78 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list bisect tests; Perl not available'
+	test_done
+fi
+
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 0d7055d46d4..02dd4127aff 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list topo-order tests; Perl not available'
+	test_done
+fi
+
 list_duplicates()
 {
     "$@" | sort | uniq -d
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index bad02cf5b83..6131c361094 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list with bad commit tests; Perl not available'
+	test_done
+fi
+
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 39793cbbd66..8074185742c 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success '--reverse --parents --full-history combines correctly' '
+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
 	git rev-list --parents --full-history main -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '
 	test_cmp expected actual
 	'
 
-test_expect_success '--boundary does too' '
+test_expect_success PERL_TEST_HELPERS '--boundary does too' '
 	git rev-list --boundary --parents --full-history main ^root -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --boundary --reverse --parents --full-history \
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 22dfd6d978e..eb98b3919c8 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list unexpected objects tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup well-formed objects' '
 	blob="$(printf "foo" | git hash-object -w --stdin)" &&
 	tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 3385fe9f130..6a74be576a2 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list disk usage tests; Perl not available'
+	test_done
+fi
+
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a5c77943854..732a4d3171e 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping for-each-ref tests; Perl not available'
+	test_done
+fi
+
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 932c26cb45b..49aae183829 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success 'setup large log output' '
+test_expect_success PERL_TEST_HELPERS 'setup large log output' '
 	perl -e "
 		print \"this is a long commit message\" x 50000
 	" >commit-msg &&
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 0c605fd271a..14069600a2f 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping submodule dash URL tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index b2070d4e39f..14c41b2cb7c 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success 'status -z implies porcelain' '
+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
 	git status --porcelain |
 	perl -pe "s/\012/\000/g" >expect &&
 	git status -z >output &&
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index 90ebb64f46e..b2730d200c8 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,6 +4,12 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping grep binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index d7167f55397..609845aeb1e 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping annotate tests; Perl not available'
+	test_done
+fi
+
 PROG='git annotate'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index e98993276a6..b40199df231 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 07a287ffd3e..5cb16872081 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,6 +4,12 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame textconv tests; Perl not available'
+	test_done
+fi
+
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh
index c66494f5ba7..388057245c8 100755
--- a/t/t8011-blame-split-file.sh
+++ b/t/t8011-blame-split-file.sh
@@ -81,7 +81,7 @@ do
 		git blame --root -C --$output combined >output
 	'
 
-	test_expect_success "$output output finds correct commits" '
+	test_expect_success PERL_TEST_HELPERS "$output output finds correct commits" '
 		generate_expect >expect <<-\EOF &&
 		5 base
 		1 modified
@@ -93,7 +93,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct filenames" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct filenames" '
 		generate_expect >expect <<-\EOF &&
 		11 one
 		11 two
@@ -102,7 +102,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct previous pointer" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct previous pointer" '
 		generate_expect >expect <<-EOF &&
 		5 NONE
 		1 $(git rev-parse modified^) one
diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh
index c3a5f6d01ff..3d77352650f 100755
--- a/t/t8012-blame-colors.sh
+++ b/t/t8012-blame-colors.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index 067b15bad25..a9d38be997c 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' '
+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success 'change file but in unrelated area' "
+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
 	perl -i.bak -p -e 's/^4\$/4444/' file &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 40427883ec6..0781a8d6ace 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '
 	(cd result && git show main:foo)
 '
 
-test_expect_success 'fast-export quotes pathnames' '
+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '
 	git init crazy-paths &&
 	test_config -C crazy-paths core.protectNTFS false &&
 	(cd crazy-paths &&
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index 36566ace21b..f619b60f226 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success 'shell complains of overlong commands' '
+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
 	perl -e "print \"a\" x 2**12 for (0..2**19)" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a62699d6c79..59162a3c834 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1706,6 +1706,7 @@ test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
 test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
 test -n "$GIT_VALGRIND_ENABLED" && test_set_prereq VALGRIND
+test -n "$PERL_PATH" && test_set_prereq PERL_TEST_HELPERS
 
 if test -z "$GIT_TEST_CHECK_CACHE_TREE"
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 07/20] t: adapt existing PERL prerequisites
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (5 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

A couple of our tests depend on the PERL prerequisite even though it
isn't needed. These tests fall into one of the following classes:

  - The underlying logic used to be implemented in Perl but isn't
    anymore. Here we can simply drop the dependency altogether.

  - The test logic used to depend on Perl but doesn't anymore. Again, we
    can simply drop the dependency.

  - The test logic still relies on a Perl interpreter. These tests
    should use the newly introduced PERL_TEST_HELPERS prerequisite.

Adapt test cases accordingly.

Note that in t1006 we have to introduce another new prerequisite
depending on whether or not the IPC::Open2 module is available. Funny
enough, when starting to use `test_lazy_prereq` to do so we also get a
conflict of variables with the "script" variable that contains the Perl
logic because `test_run_lazy_prereq_` also sets that variable. We thus
rename the variable in t1006 to "perl_script".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh                 | 10 +++++-----
 t/t0090-cache-tree.sh                 |  4 ++--
 t/t1006-cat-file.sh                   | 14 +++++++++-----
 t/t7501-commit-basic-functionality.sh |  6 +++---
 4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9c3738ebb3f..4a892a91780 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'
 	)
 '
 
-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
+test_expect_success 'invalid process filter must fail (and not hang!)' '
 	test_config_global filter.protocol.process cat &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
@@ -1111,19 +1111,19 @@ do
 	branch) opt='-f HEAD' ;;
 	esac
 
-	test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
+	test_expect_success TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
 		test_delayed_checkout_progress test_terminal git checkout $opt
 	'
 
-	test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" '
+	test_expect_success "delayed checkout omits progress on non-tty ($mode checkout)" '
 		test_delayed_checkout_progress ! git checkout $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
+	test_expect_success TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
+	test_expect_success TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&
 		test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt
 	'
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index ab80c9ef135..d9015882946 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '
 	test_cache_tree
 '
 
-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
 	test_when_finished "git reset --hard" &&
 	cat <<-\EOT >foo.c &&
 	int foo()
@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
 	test_cache_tree expected.status
 '
 
-test_expect_success PERL 'commit -p with shrinking cache-tree' '
+test_expect_success 'commit -p with shrinking cache-tree' '
 	mkdir -p deep/very-long-subdir &&
 	echo content >deep/very-long-subdir/file &&
 	git add deep &&
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index a574da3df53..0a22b0a7b8e 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '
 	grep "^fatal:.*flush is only for --buffer mode.*" err
 '
 
-script='
+perl_script='
 use warnings;
 use strict;
 use IPC::Open2;
@@ -1345,12 +1345,16 @@ $? == 0 or die "\$?=$?";
 
 expect="$hello_oid blob $hello_size"
 
-test_expect_success PERL '--batch-check is unbuffered by default' '
-	perl -e "$script" -- --batch-check $hello_oid "$expect"
+test_lazy_prereq PERL_IPC_OPEN2 '
+	perl -MIPC::Open2 -e "exit 0"
 '
 
-test_expect_success PERL '--batch-command info is unbuffered by default' '
-	perl -e "$script" -- --batch-command $hello_oid "$expect" "info "
+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-check $hello_oid "$expect"
+'
+
+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-command $hello_oid "$expect" "info "
 '
 
 test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index cc12f99f115..a37509f0043 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '
 	test_must_fail git commit -m foo -a file
 '
 
-test_expect_success PERL 'can use paths with --interactive' '
+test_expect_success 'can use paths with --interactive' '
 	echo bong-o-bong >file &&
 	# 2: update, 1:st path, that is all, 7: quit
 	test_write_lines 2 1 "" 7 |
@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '
 	grep Rubber.Duck output
 '
 
-test_expect_success PERL 'interactive add' '
+test_expect_success 'interactive add' '
 	echo 7 | test_must_fail git commit --interactive >out &&
 	grep "What now" out
 '
 
-test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
+test_expect_success "commit --interactive doesn't change index if editor aborts" '
 	echo zoo >file &&
 	test_must_fail git diff --exit-code >diff1 &&
 	test_write_lines u "*" q |

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 08/20] meson: stop requiring Perl when tests are enabled
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (6 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The Perl interpreter used to be a strict dependency for running our test
suite. This requirement is explicit in the Meson build system, where we
require Perl to be present unless tests have been disabled.

With the preceding commits we have loosened this restriction so that it
is now possible to run tests when Perl is unavailable. Loosen the above
requirement accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index efe2871c9db..d6e27b236fa 100644
--- a/meson.build
+++ b/meson.build
@@ -772,7 +772,7 @@ endif
 # features. It is optional if you want to neither execute tests nor use any of
 # these optional features.
 perl_required = get_option('perl')
-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
   perl_required = true
 endif
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 09/20] Makefile: stop requiring Perl when running tests
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (7 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The Makefile for our tests has a couple of targets that depend on Perl.
Adapt those targets to only run conditionally in case Perl is available
on the system so that it becomes possible to run the test suite without
Perl.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/Makefile | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/t/Makefile b/t/Makefile
index 2994eb5fa9a..791e0a09789 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT
 
 all:: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean check-chainlint check-meson $(TEST_LINT)
+test: pre-clean check-meson $(TEST_LINT)
 	$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
 
+ifneq ($(PERL_PATH),)
+test: check-chainlint
+prove: check-chainlint
+endif
+
 failed:
 	@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \
 		grep -l '^failed [1-9]' *.counts | \
 		sed -n 's/\.counts$$/.sh/p') && \
 	test -z "$$failed" || $(MAKE) $$failed
 
-prove: pre-clean check-chainlint $(TEST_LINT)
+prove: pre-clean $(TEST_LINT)
 	@echo "*** prove (shell & unit tests) ***"
 	@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
 	$(MAKE) clean-except-prove-cache
@@ -132,8 +137,13 @@ check-meson:
 		fi; \
 	done
 
-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
+test-lint: test-lint-duplicates test-lint-executable \
 	test-lint-filenames
+ifneq ($(PERL_PATH),)
+test-lint: test-lint-shell-syntax
+else
+GIT_TEST_CHAIN_LINT = 0
+endif
 ifneq ($(GIT_TEST_CHAIN_LINT),0)
 test-lint: test-chainlint
 endif

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 10/20] t: refactor tests depending on Perl transliteration operator
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (8 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

We have a bunch of tests that use Perl to perform character
transliteration via the "y/" or "tr/" operator. These usecases can be
trivially replaced with tr(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-sha1.sh    |  4 ++--
 t/lib-diff.sh            |  4 ++--
 t/t3300-funny-names.sh   | 12 ++++++------
 t/t4020-diff-external.sh |  6 +++---
 t/t4103-apply-binary.sh  | 12 +++---------
 t/t4116-apply-reverse.sh | 10 ++--------
 t/t4200-rerere.sh        |  2 +-
 7 files changed, 19 insertions(+), 31 deletions(-)

diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index bf387d3db14..f03b784ddc2 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -15,7 +15,7 @@ do
 			{
 				test -z "$pfx" || echo "$pfx"
 				dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-				perl -pe 'y/\000/g/'
+				tr "\000" "g"
 			} | ./t/helper/test-tool $sha1 $cnt
 		)
 		if test "$expect" = "$actual"
@@ -61,7 +61,7 @@ do
 		{
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-			perl -pe 'y/\000/g/'
+			tr "\000" "g"
 		} | sha1sum |
 		sed -e 's/ .*//'
 	)
diff --git a/t/lib-diff.sh b/t/lib-diff.sh
index c4606bd4b7f..12b3c8fcc6a 100644
--- a/t/lib-diff.sh
+++ b/t/lib-diff.sh
@@ -21,8 +21,8 @@ compare_diff_raw_z () {
     # Also we do not check SHA1 hash generation in this test, which
     # is a job for t0000-basic.sh
 
-    perl -pe 'y/\000/\012/' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
-    perl -pe 'y/\000/\012/' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
+    tr "\000" "\012" <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
+    tr "\000" "\012" <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 502b1572059..dd0586b0073 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
+test_expect_success 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
 	tabs	," (dq) and spaces
 	EOF
 	git ls-files -z >ls-files.z &&
-	perl -pe "y/\000/\012/" <ls-files.z >current &&
+	tr "\000" "\012" <ls-files.z >current &&
 	test_cmp expected current
 '
 
@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
+test_expect_success 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-index -z --name-status $t0 >diff-index.z &&
-	perl -pe "y/\000/\012/" <diff-index.z >current &&
+	tr "\000" "\012" <diff-index.z >current &&
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
+test_expect_success 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-tree -z --name-status $t0 $t1 >diff-tree.z &&
-	perl -pe y/\\000/\\012/ <diff-tree.z >current &&
+	tr "\000" "\012" <diff-tree.z >current &&
 	test_cmp expected current
 '
 
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 189294de7ef..c8a23d51483 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet
 check_external_diff   1 empty  empty 1 on  --quiet
 check_external_diff 128 empty  error 2 on  --quiet
 
-echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
+echo NULZbetweenZwords | tr "Z" "\000" > file
 
-test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
+test_expect_success 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff --cached' '
+test_expect_success 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index 4894605db7a..8e302a5a57e 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping ignores tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
@@ -32,10 +26,10 @@ test_expect_success 'setup' '
 	git commit -m "Initial Version" 2>/dev/null &&
 
 	git checkout -b binary &&
-	perl -pe "y/x/\000/" <file1 >file3 &&
+	tr "x" "\000" <file1 >file3 &&
 	cat file3 >file4 &&
 	git add file2 &&
-	perl -pe "y/\000/v/" <file3 >file1 &&
+	tr "y" "\000" <file3 >file1 &&
 	rm -f file2 &&
 	git update-index --add --remove file1 file2 file3 file4 &&
 	git commit -m "Second Version" &&
@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '
 	test -z "$(git diff --name-status binary -- file3)"
 '
 
-test_expect_success 'reject truncated binary diff' '
+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '
 	do_reset &&
 
 	# this length is calculated to get us very close to
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 6f414ad27f5..1e7beab0016 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,23 +10,17 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply reverse tests; Perl not available'
-	test_done
-fi
-
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
-	perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 &&
+	tr "ijk" "\000\001\002" <file1 >file2 &&
 
 	git add file1 file2 &&
 	git commit -m initial &&
 	git tag initial &&
 
 	test_write_lines a b c g h i J K L m o n p q >file1 &&
-	perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 &&
+	tr "mon" "\000\001\002" <file1 >file2 &&
 
 	git commit -a -m second &&
 	git tag second &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 50fe8b0fd05..7fcca9ddad5 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '
 
 test_expect_success 'rerere clear' '
 	mv $rr/postimage .git/post-saved &&
-	echo "$sha1	a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
+	echo "$sha1	a1" | tr "\012" "\000" >.git/MERGE_RR &&
 	git rerere clear &&
 	! test -d $rr
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (9 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-24 16:16   ` Phillip Wood
  2025-03-20  9:35 ` [PATCH 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

We have a bunch of tests that use Perl to perform substitution via the
"s/" operator. These usecases can be trivially replaced with sed(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        | 10 ++--------
 t/t4029-diff-trailing-space.sh            |  5 +++--
 t/t4200-rerere.sh                         | 12 +++---------
 t/t5303-pack-corruption-resilience.sh     | 10 ++++++----
 t/t5310-pack-bitmaps.sh                   |  4 ++--
 t/t5534-push-signed.sh                    |  4 ++--
 t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------
 t/t7416-submodule-dash-url.sh             |  9 ++-------
 t/t7508-status.sh                         |  4 ++--
 t/t8006-blame-textconv.sh                 |  8 +-------
 t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------
 11 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 1aaa6bf5ae8..7d5a0458818 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,12 +5,6 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping ignores tests; Perl not available'
-	test_done
-fi
-
 init_vars () {
 	global_excludes="global-excludes"
 }
@@ -45,11 +39,11 @@ test_stderr () {
 }
 
 broken_c_unquote () {
-	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
+	<"$1" sed -e 's/^"//' -e 's/\\//' -e 's/"$//' | tr '\n' '\0'
 }
 
 broken_c_unquote_verbose () {
-	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
+	<"$1" sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' | tr ':\t\n' '\000'
 }
 
 stderr_contains () {
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index a92a42990b1..db75998e35f 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success PERL_TEST_HELPERS "$test_description" '
+test_expect_success "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
 	git config --bool diff.suppressBlankEmpty true &&
 	git diff f > actual &&
 	test_cmp exp actual &&
-	perl -i.bak -p -e "s/^\$/ /" exp &&
+	sed "s/^\$/ /" <exp >exp.munged &&
+	mv exp.munged exp &&
 	git config --bool diff.suppressBlankEmpty false &&
 	git diff f > actual &&
 	test_cmp exp actual &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 7fcca9ddad5..bacb93d014f 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rerere tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
 	test_might_fail git config --unset rerere.enabled &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep "^=======\$" $rr/preimage &&
 	! test -f $rr/postimage &&
@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
 	git reset --hard &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep ^=======$ $rr/preimage
 '
@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
 	git config rerere.enabled true &&
 	git reset --hard &&
 	test_must_fail git merge first &&
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1
 '
 
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index ac5e370e1e4..07382797bbb 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
+test_expect_success 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
+	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	test_must_fail git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
@@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
+test_expect_success 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
+	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 81987296235..9033d72b8c7 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -421,7 +421,7 @@ test_bitmap_cases () {
 
 			# mark the commits which did not receive bitmaps as preferred,
 			# and generate the bitmap again
-			perl -pe "s{^}{create refs/tags/include/$. }" <before |
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
 				git update-ref --stdin &&
 			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
 
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 342d0423c92..d5c0d00114e 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
 	# Tweak the push output to make the push option outside the cert
 	# different, then replay it on a fresh dst, checking that ff is not
 	# deleted.
-	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
+	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
 	git -C dst config receive.advertisepushoptions 1 &&
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index 6131c361094..12329aab388 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list with bad commit tests; Perl not available'
-	test_done
-fi
-
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
    first_commit=$(git rev-parse HEAD~3)
    '
 
-test_expect_success 'corrupt second commit object' \
-   '
-   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
-   test_must_fail git fsck --full
-   '
+test_expect_success 'corrupt second commit object' '
+	for p in .git/objects/pack/*.pack
+	do
+		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
+		mv "$p.munged" "$p" ||
+		return 1
+	done &&
+	test_must_fail git fsck --full
+'
 
 test_expect_success 'rev-list should fail' '
 	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 14069600a2f..00b81d349b9 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping submodule dash URL tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
 '
 
 test_expect_success 'remove ./ protection from .gitmodules url' '
-	perl -i -pe "s{\./}{}" .gitmodules &&
+	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
+	mv .gitmodules.munged .gitmodules &&
 	git commit -am "drop protection"
 '
 
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 14c41b2cb7c..cdc1d6fcc78 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
+test_expect_success 'status -z implies porcelain' '
 	git status --porcelain |
-	perl -pe "s/\012/\000/g" >expect &&
+	tr "\012" "\000" >expect &&
 	git status -z >output &&
 	test_cmp expect output
 '
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 5cb16872081..810dac18f56 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,12 +4,6 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping blame textconv tests; Perl not available'
-	test_done
-fi
-
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
@@ -17,7 +11,7 @@ find_blame() {
 cat >helper <<'EOF'
 #!/bin/sh
 grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
-"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
+sed 's/^bin: /converted: /' <"$1"
 EOF
 chmod +x helper
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index a9d38be997c..9afdb45b1cc 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
+test_expect_success '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
 	(cd tmp &&
-		perl -i.bak -p -e "s/^58$/5588/" file &&
-		perl -i.bak -p -e "s/^61$/6611/" file &&
+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
+		mv file.munged file &&
 		poke file &&
 		test x"$(sed -n -e 58p < file)" = x5588 &&
 		test x"$(sed -n -e 61p < file)" = x6611 &&
@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
+test_expect_success 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
-	perl -i.bak -p -e 's/^4\$/4444/' file &&
-	perl -i.bak -p -e 's/^7\$/7777/' file &&
+	sed -e 's/^4\$/4444/' \
+	    -e 's/^7\$/7777/' \
+		<file >file.munged &&
+	mv file.munged file &&
 	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
 	git commit -m '4 => 4444, 7 => 7777' file &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 12/20] t: refactor tests depending on Perl to print data
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (10 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20 19:33   ` Eric Sunshine
  2025-03-20  9:35 ` [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

A bunch of tests rely on Perl to print data in various different ways.
These usages fall into the following categories:

  - Print data conditionally by matching patterns. These usecases can be
    converted to use awk(1) rather easily.

  - Print data repeatedly. These usecases can typically be converted to
    use a combination of `test-tool genzeros` and sed(1).

  - Print data in reverse. These usecases can be converted to use
    awk(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0610-reftable-basics.sh          |  7 +++----
 t/t0613-reftable-write-options.sh   |  4 ++--
 t/t1010-mktree.sh                   |  8 ++++----
 t/t4150-am.sh                       | 10 +++++-----
 t/t5300-pack-object.sh              | 16 +++++-----------
 t/t5326-multi-pack-bitmaps.sh       |  6 +++---
 t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------
 t/t5410-receive-pack-alternates.sh  |  6 +++---
 t/t5701-git-serve.sh                |  7 +++++--
 t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------
 t/t6115-rev-list-du.sh              |  8 +-------
 t/t7006-pager.sh                    |  8 ++++----
 t/t8002-blame.sh                    |  2 +-
 t/t9850-shell.sh                    |  4 ++--
 14 files changed, 51 insertions(+), 67 deletions(-)

diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 5e0a1fa176d..080797af1d0 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
+test_expect_success 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+
+	awk "BEGIN { for (i = 0; i < 50000; i++) print \"this is a long commit message\" }" >commit-msg &&
 	git -C repo commit --allow-empty --file=../commit-msg
 '
 
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index fa1e2f9eef8..42aa1592f87 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
+test_expect_success 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
 		cd repo &&
 		test_commit A &&
-		perl -e "print \"a\" x 500" >logmsg &&
+		test-tool genzeros 500 | tr "\000" "a" >logmsg &&
 		cat >expect <<-EOF &&
 		fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large
 		EOF
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 4977998e205..e9973f74949 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
-	perl -e "print reverse <>" <top |
+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+	sort -r <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
-	perl -e "print reverse <>" <top.withsub |
+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+	sort -r <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
 '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 4794510d70d..2ae93d3c967 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
+test_expect_success 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'
     Body test" --author="$LONG <long@example.com>" &&
 	git format-patch --stdout -1 >patch &&
 	# bump from, date, and subject down to in-body header
-	perl -lpe "
-		if (/^From:/) {
+	awk "
+		/^From:/{
 			print \"From: x <x\@example.com>\";
 			print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
 			print \"Subject: x\n\";
-		}
-	" patch >msg &&
+		}; 1
+	" <patch >msg &&
 	git checkout HEAD^ &&
 	git am msg &&
 	# Ensure that the author and full message are present
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 143856c29f1..362b05441af 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,17 +7,11 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pack-object tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	rm -f .git/index* &&
-	perl -e "print \"a\" x 4096;" >a &&
-	perl -e "print \"b\" x 4096;" >b &&
-	perl -e "print \"c\" x 4096;" >c &&
+	test-tool genzeros 4096 | tr "\000" "a" >a &&
+	test-tool genzeros 4096 | tr "\000" "b" >b &&
+	test-tool genzeros 4096 | tr "\000" "c" >c &&
 	test-tool genrandom "seed a" 2097152 >a_big &&
 	test-tool genrandom "seed b" 2097152 >b_big &&
 	git update-index --add a a_big b b_big c &&
@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'
 # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>
 # e.g.: check_deltas stderr -gt 0
 check_deltas() {
-	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' <"$1") &&
 	shift &&
 	if ! test "$deltas" "$@"
 	then
@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '
 	check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
 '
 
-test_expect_success 'compare delta flavors' '
+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '
 	perl -e '\''
 		defined($_ = -s $_) or die for @ARGV;
 		exit 1 if $ARGV[0] <= $ARGV[1];
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 627f8b4efdc..e5d52de4bd3 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {
 			comm -13 bitmaps commits >before &&
 			test_line_count = 1 before &&
 
-			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
-				<before | git update-ref --stdin &&
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
+			git update-ref --stdin &&
 
 			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
 			rm -fr $midx &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 1059ff45fe4..df13a18c5c7 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
-	test_done
-fi
-
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {
 
 tag_everything () {
 	git rev-list --all --no-object-names >in &&
-	perl -lne '
-		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
-	' <in | git update-ref --stdin
+	sed 's|\(.*\)|create refs/tags/\1 \1|' <in |
+	git update-ref --stdin
 }
 
 test_expect_success 'setup' '
@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '
 	test_cmp expect actual
 '
 
-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
 	test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
 	test_config bitmapPseudoMerge.test.maxMerges 1 &&
 	test_config bitmapPseudoMerge.test.stableThreshold never &&
@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 			test_commit_bulk 16 &&
 
 			git rev-list HEAD~16.. >in &&
-
-			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" <in |
 			git update-ref --stdin || return 1
 		done &&
 
@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 		do
 			test_pseudo_merge_commits $m >oids &&
 			grep -f oids refs |
-			perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
+			sed -n "s|refs/remotes/\([0-9][0-9]*\)/|\1|p" &&
 			sort -u || return 1
 		done >remotes &&
 
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 6a009fdcd71..4e82fd102e3 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -17,10 +17,10 @@ test_expect_success 'setup' '
 '
 
 extract_haves () {
-	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+	depacketize | sed -n 's/^\([^ ][^ ]*\) \.have/\1/p'
 }
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
+test_expect_success 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
+test_expect_success 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 200bf06ecb3..d4c28bae39e 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
+test_expect_success 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 		echo command=ls-refs &&
 		echo object-format=$(test_oid algo) &&
 		echo 0001 &&
-		perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
+		awk "{
+			for (i = 1; i <= 65536; i++)
+				print \"ref-prefix refs/heads/\", \$i
+		}" &&
 		echo 0000
 	} |
 	test-tool pkt-line pack >in &&
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 8074185742c..273196f52b5 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
-	git rev-list --parents --full-history main -- foo |
-		perl -e "print reverse <>" > expected &&
+reverse () {
+	awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'
+}
+
+test_expect_success '--reverse --parents --full-history combines correctly' '
+	git rev-list --parents --full-history main -- foo | reverse >expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
 		> actual &&
 	test_cmp expected actual
 	'
 
-test_expect_success PERL_TEST_HELPERS '--boundary does too' '
-	git rev-list --boundary --parents --full-history main ^root -- foo |
-		perl -e "print reverse <>" > expected &&
+test_expect_success '--boundary does too' '
+	git rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&
 	git rev-list --boundary --reverse --parents --full-history \
 		main ^root -- foo > actual &&
 	test_cmp expected actual
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 6a74be576a2..04c577dad69 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list disk usage tests; Perl not available'
-	test_done
-fi
-
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '
 disk_usage_slow () {
 	git rev-list --no-object-names "$@" |
 	git cat-file --batch-check="%(objectsize:disk)" |
-	perl -lne '$total += $_; END { print $total}'
+	awk '{ i += $1 } END { print i }'
 }
 
 # check behavior with given rev-list options; note that
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 49aae183829..9717e825f0d 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success PERL_TEST_HELPERS 'setup large log output' '
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+test_expect_success 'setup large log output' '
+	test-tool genzeros 50000 |
+	tr "\000" "a" |
+	sed "s/a/this is a long commit message/g" >commit-msg &&
 	git commit --allow-empty -F commit-msg
 '
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index b40199df231..0b7548c8e75 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '
 		expect=$1 && shift &&
 		echo $sha1 | cut -c 1-$expect >expect &&
 		git blame "$@" abbrev.t >actual &&
-		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" <actual >actual.sha &&
 		test_cmp expect actual.sha
 	}
 '
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index f619b60f226..21c3af48bd0 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
-	perl -e "print \"a\" x 2**12 for (0..2**19)" |
+test_expect_success 'shell complains of overlong commands' '
+	test-tool genzeros | tr "\000" "a" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (11 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20 19:37   ` Eric Sunshine
  2025-03-24 16:16   ` Phillip Wood
  2025-03-20  9:35 ` [PATCH 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
                   ` (9 subsequent siblings)
  22 siblings, 2 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

We have a couple of tests that depend on Perl for textconv scripts.
Refactor these tests to instead be implemented via shell utilities so
that we can drop a couple of PERL_TEST_HELPERS prerequisites.

Note that not all of the conversions are a one-to-one equivalent to the
previous textconv scripts. But that's not really needed in the first
place: we only care that the textconv script does something, and that
can be verified trivially without having a full-blown invocation of
hexdump. So at times, the implementation of the textconv scripts is
reduced to their bare minimum.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t4030-diff-textconv.sh       | 15 +++------------
 t/t4031-diff-rewrite-binary.sh | 19 +++++++------------
 t/t7815-grep-binary.sh         | 15 +++------------
 3 files changed, 13 insertions(+), 36 deletions(-)

diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index c7d8eb12453..f904fc19f69 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping diff textconv tests; Perl not available'
-	test_done
-fi
-
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
 +1
 EOF
 
-cat >hexdump <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-chmod +x hexdump
-
 test_expect_success 'setup binary file with history' '
+	write_script hexdump <<-\EOF &&
+	tr "\000\001" "01" <"$1"
+	EOF
 	test_commit --printf one file "\\0\\n" &&
 	test_commit --printf --append two file "\\01\\n"
 '
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index cbe50b15772..15e012ccc7c 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
 	grep " rewrite file" diff
 '
 
-{
-	echo "#!$SHELL_PATH"
-	cat <<'EOF'
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-} >dump
-chmod +x dump
-
 test_expect_success 'setup textconv' '
+	write_script dump <<-\EOF &&
+	test-tool hexdump <"$1"
+	EOF
 	echo file diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
+test_expect_success 'rewrite diff respects textconv' '
 	git diff -B >diff &&
-	grep "dissimilarity index" diff &&
-	grep "^-61" diff &&
-	grep "^-0" diff
+	test_grep "dissimilarity index" diff &&
+	test_grep "^-3d 0a 00" diff &&
+	test_grep "^+3d 0a 01" diff
 '
 
 test_done
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index b2730d200c8..3bd91da9707 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,12 +4,6 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping grep binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
 	test_cmp expect actual
 '
 
-cat >nul_to_q_textconv <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
-EOF
-chmod +x nul_to_q_textconv
-
 test_expect_success 'setup textconv filters' '
+	write_script nul_to_q_textconv <<-\EOF &&
+	tr "\000" "Q" <"$1"
+	EOF
 	echo a diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (12 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
stdin. Refactor it to instead use awk(1) so that we drop the
PERL_TEST_HELPERS prerequisite in users of this library.

Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
now that the test suite doesn't bail out early anymore in case the
prerequisite isn't set.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-gpg.sh            |  6 +-----
 t/t6300-for-each-ref.sh | 21 ++++++++++-----------
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 3845b6ac449..937b876bd05 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '
 '
 
 sanitize_pgp() {
-	perl -ne '
-		/^-----END PGP/ and $in_pgp = 0;
-		print unless $in_pgp;
-		/^-----BEGIN PGP/ and $in_pgp = 1;
-	'
+	sed "/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}"
 }
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 732a4d3171e..5db7038c417 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping for-each-ref tests; Perl not available'
-	test_done
-fi
-
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '
 	test_must_fail git for-each-ref --format="%(raw)" --tcl
 '
 
-test_expect_success '%(raw) with --perl' '
+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
 	git for-each-ref --format="\$name= %(raw);
 print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
 	cmp blob1 actual &&
@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '
 '
 
 test_trailer_option () {
+	if test "$#" -eq 3
+	then
+		prereq="$1"
+		shift
+	fi &&
 	title=$1 option=$2
 	cat >expect
-	test_expect_success "$title" '
+	test_expect_success $prereq "$title" '
 		git for-each-ref --format="%($option)" refs/heads/main >actual &&
 		test_cmp expect actual &&
 		git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
@@ -1452,7 +1451,7 @@ test_trailer_option () {
 	'
 }
 
-test_trailer_option '%(trailers:unfold) unfolds trailers' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
 	'trailers:unfold' <<-EOF
 	$(unfold <trailers)
 
@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \
 
 	EOF
 
-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
 	'trailers:only,unfold' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 
 	EOF
 
-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
 	'trailers:unfold,only' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (13 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20 19:41   ` Eric Sunshine
  2025-03-20  9:35 ` [PATCH 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `name_from_description()` test helper uses Perl to munge a given
description and convert it into a name. Refactor it to instead use a
combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
prerequisites in users of this library.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-t6000.sh                 | 13 ++++++-------
 t/t6002-rev-list-bisect.sh     |  6 ------
 t/t6003-rev-list-topo-order.sh |  6 ------
 3 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
index fba6778ca35..5191ebb30b8 100644
--- a/t/lib-t6000.sh
+++ b/t/lib-t6000.sh
@@ -109,13 +109,12 @@ check_output () {
 # All alphanums translated into -'s which are then compressed and stripped
 # from front and back.
 name_from_description () {
-	perl -pe '
-		s/[^A-Za-z0-9.]/-/g;
-		s/-+/-/g;
-		s/-$//;
-		s/^-//;
-		y/A-Z/a-z/;
-	'
+	sed \
+		-e 's/[^A-Za-z0-9.]/-/g' \
+		-e 's/--*/-/g' \
+		-e 's/-$//' \
+		-e 's/^-//' |
+	tr 'A-Z' 'a-z'
 }
 
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index 5e1482aff78..daa009c9a1b 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list bisect tests; Perl not available'
-	test_done
-fi
-
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 02dd4127aff..0d7055d46d4 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list topo-order tests; Perl not available'
-	test_done
-fi
-
 list_duplicates()
 {
     "$@" | sort | uniq -d

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 16/20] t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (14 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

Our Apache HTTPD setup exposes an "one_time_perl" endpoint to access
repositories. If used, we execute the "apply-one-time-perl.sh" CGI
script that checks whether we have a "one-time-perl" script. If so, that
script gets executed so that it can munge what would be served. Once
done, the script gets removed so that it doesn't execute a second time.

As the name says, this functionality expects the user to pass a Perl
script. This isn't really necessary though: we can just as easily
implement the same thing with arbitrary scripts.

Refactor the code so that we instead expect an arbitrary script to
exist and rename the functionality to "one-time-script". Adapt callers
to use shell utilities instead of Perl so that we can drop the
PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-httpd.sh                       |  2 +-
 t/lib-httpd/apache.conf              |  6 ++---
 t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------
 t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++
 t/t5537-fetch-shallow.sh             | 17 ++++++-------
 t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------
 t/t5702-protocol-v2.sh               | 27 +++++++++++---------
 t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---
 8 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index d83bafeab32..5091db949b7 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -165,7 +165,7 @@ prepare_httpd() {
 	install_script broken-smart-http.sh
 	install_script error-smart-http.sh
 	install_script error.sh
-	install_script apply-one-time-perl.sh
+	install_script apply-one-time-script.sh
 	install_script nph-custom-auth.sh
 
 	ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 022276a6b9a..e631ab0eb5e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
-<LocationMatch /one_time_perl/>
+<LocationMatch /one_time_script/>
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1
 ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Directory ${GIT_EXEC_PATH}>
 	Options FollowSymlinks
@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Files error.sh>
   Options ExecCGI
 </Files>
-<Files apply-one-time-perl.sh>
+<Files apply-one-time-script.sh>
 	Options ExecCGI
 </Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
deleted file mode 100644
index d7f9fed6aee..00000000000
--- a/t/lib-httpd/apply-one-time-perl.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# If "one-time-perl" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,
-# using the contents of "one-time-perl" as the perl command to be run. If the
-# response was modified as a result, delete "one-time-perl" so that subsequent
-# HTTP responses are no longer modified.
-#
-# This can be used to simulate the effects of the repository changing in
-# between HTTP request-response pairs.
-if test -f one-time-perl
-then
-	LC_ALL=C
-	export LC_ALL
-
-	"$GIT_EXEC_PATH/git-http-backend" >out
-	"$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
-
-	if cmp -s out out_modified
-	then
-		cat out
-	else
-		cat out_modified
-		rm one-time-perl
-	fi
-else
-	"$GIT_EXEC_PATH/git-http-backend"
-fi
diff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh
new file mode 100644
index 00000000000..b1682944e28
--- /dev/null
+++ b/t/lib-httpd/apply-one-time-script.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# If "one-time-script" exists in $HTTPD_ROOT_PATH, run the script on the HTTP
+# response. If the response was modified as a result, delete "one-time-script"
+# so that subsequent HTTP responses are no longer modified.
+#
+# This can be used to simulate the effects of the repository changing in
+# between HTTP request-response pairs.
+if test -f one-time-script
+then
+	LC_ALL=C
+	export LC_ALL
+
+	"$GIT_EXEC_PATH/git-http-backend" >out
+	./one-time-script out >out_modified
+
+	if cmp -s out out_modified
+	then
+		cat out
+	else
+		cat out_modified
+		rm one-time-script
+	fi
+else
+	"$GIT_EXEC_PATH/git-http-backend"
+fi
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 77d20d19110..9dfcfb46df0 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before
 	git -C "$REPO" config protocol.version 2 &&
 	git -C client config protocol.version 2 &&
 
-	git -C client fetch --depth=2 "$HTTPD_URL/one_time_perl/repo" main:a_branch &&
+	git -C client fetch --depth=2 "$HTTPD_URL/one_time_script/repo" main:a_branch &&
 
 	# Craft a situation in which the server sends back an unshallow request
 	# with an empty packfile. This is done by refetching with a shorter
 	# depth (to ensure that the packfile is empty), and overwriting the
 	# shallow line in the response with the unshallow line we want.
-	printf "$(test_oid perl)" \
-	       "$(git -C "$REPO" rev-parse HEAD)" \
-	       "$(git -C "$REPO" rev-parse HEAD^)" \
-	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" <"\$1"
+	EOF
 	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
-		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
+		fetch --depth=1 "$HTTPD_URL/one_time_script/repo" \
 		main:a_branch &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl" &&
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script" &&
 
 	# Ensure that the resulting repo is consistent, despite our failure to
 	# fetch.
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index bc7e0fec8dc..f878592a377 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -737,21 +737,25 @@ intersperse () {
 	sed 's/\(..\)/'$1'\1/g'
 }
 
-# Create a one-time-perl command to replace the existing packfile with $1.
+# Create a one-time-script command to replace the existing packfile with $1.
 replace_packfile () {
-	# The protocol requires that the packfile be sent in sideband 1, hence
-	# the extra \x01 byte at the beginning.
-	cp $1 "$HTTPD_ROOT_PATH/one-time-pack" &&
-	echo 'if (/packfile/) {
-		print;
-		my $length = -s "one-time-pack";
-		printf "%04x\x01", $length + 5;
-		print `cat one-time-pack` . "0000";
-		last
-	}' >"$HTTPD_ROOT_PATH/one-time-perl"
+	cp "$1" one-time-pack &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	if grep packfile "\$1" >/dev/null
+	then
+		sed '/packfile/q' <"\$1" &&
+		# The protocol requires that the packfile be sent in sideband
+		# 1, hence the extra \001 byte at the beginning.
+		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
+		cat "$PWD/one-time-pack" &&
+		printf "0000"
+	else
+		cat "\$1"
+	fi
+	EOF
 }
 
-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
+test_expect_success 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t
 	# section header.
 	test_config -C "$SERVER" protocol.version 2 &&
 	test_must_fail git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&
 
 	test_grep "did not send all necessary objects" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not
 
 	# Exercise to make sure it works.
 	git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&
 	! grep "missing object referenced by" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 
 	# Clone. The client has deltabase_have but not deltabase_missing.
 	git -c protocol.version=2 clone --no-checkout \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo &&
 	git -C repo hash-object -w -- "$SERVER/have.txt" &&
 
 	# Sanity check to ensure that the client does not have
@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 	grep "want $(cat deltabase_missing)" trace &&
 	! grep "want $(cat deltabase_have)" trace &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 # DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ad5e772cd72..27434b1f07a 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
+test_expect_success 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM'
 
 	# After "ready" in the acknowledgments section, pretend that a FLUSH
 	# (0000) was sent instead of a DELIM (0001).
-	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/ready/{n;s/0001/0000/;}" <"$1"
+	EOF
 
 	test_must_fail git -C http_child -c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
+test_expect_success 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect
 
 	# After the acknowledgments section, pretend that a DELIM
 	# (0001) was sent instead of a FLUSH (0000).
-	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/acknowledgments/,//{s/0000/0001/;}" <"$1"
+	EOF
 
 	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
 		-c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	grep "fetch< .*acknowledgments" log &&
 	! grep "fetch< .*ready" log &&
 	test_grep "expected no other sections to be sent after no .ready." err
@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
-	URI="$HTTPD_URL/one_time_perl/server" &&
+	URI="$HTTPD_URL/one_time_script/server" &&
 
 	setup_negotiate_only "$SERVER" "$URI" &&
 
-	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" <"$1"
+	EOF
 
 	test_must_fail git -c protocol.version=2 -C client fetch \
 		--no-tags \
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index f59d47aa6c6..ac7266126a0 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '
 		test_commit m3 &&
 		git tag -d m2 m3
 	) &&
-	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo" &&
+	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo" &&
 	git -C "$LOCAL_PRISTINE" config protocol.version 2
 '
 
@@ -481,7 +481,9 @@ inconsistency () {
 	# RPCs during a single negotiation.
 	oid1=$(git -C "$REPO" rev-parse $1) &&
 	oid2=$(git -C "$REPO" rev-parse $2) &&
-	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	sed "s/$oid1/$oid2/" <"\$1"
+	EOF
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
-	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/main/rain/" <"$1"
+	EOF
 	test_must_fail git -C local fetch 2>err &&
 
 	test_grep "fatal: remote error: unknown ref refs/heads/rain" err

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (15 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `generate_random_characters()` helper function generates N
random characters in the range 'a-z' and writes them into a file. The
logic currently uses Perl, but it can be adapted rather easily by:

  - Making `test-tool genrandom` generate an infinite stream.

  - Using `tr -dc` to strip all characters which aren't in the range of
    'a-z'.

  - Using `test_copy_bytes()` to copy the first N bytes.

This allows us to drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 4a892a91780..bf10d253ec4 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -20,8 +20,7 @@ EOF
 generate_random_characters () {
 	LEN=$1
 	NAME=$2
-	test-tool genrandom some-seed $LEN |
-		perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
+	test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME"
 }
 
 filter_git () {
@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
+test_expect_success 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
+test_expect_success 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 18/20] t0210: refactor trace2 scrubbing to not use Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (16 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The output generated by our trace2 mechanism contains several fields
that are dependent on the environment they're being run in, which makes
it somewhat harder to test it. As a countermeasure we scrub the output
and strip out any fields that contain such information.

The logic to do so is implemented in Perl, but it can be trivially
ported to instead use sed(1). Refactor the code accordingly so that we
can drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------
 t/t0210/scrub_normal.perl | 54 -----------------------------------------
 2 files changed, 43 insertions(+), 72 deletions(-)

diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index ba4c0442b85..96c68f65df2 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping trace2 tests; Perl not available'
-	test_done
-fi
-
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF
 #
 # Implicit return from cmd_<verb> function propagates <code>.
 
+scrub_normal () {
+	# Scrub the variable fields from the normal trace2 output to make
+	# testing easier:
+	#
+	#   1. Various messages include an elapsed time in the middle of the
+	#      message. Replace the time with a placeholder to simplify our
+	#      HEREDOC in the test script.
+	#
+	#   2. We expect:
+	#
+	#        start <argv0> [<argv1> [<argv2> [...]]]
+	#
+	#      where argv0 might be a relative or absolute path, with or
+	#      without quotes, and platform dependent. Replace argv0 with a
+	#      token for HEREDOC matching in the test script.
+	#
+	#   3. Likewise, the 'cmd_path' message breaks out argv[0].
+	#
+	#      This line is only emitted when RUNTIME_PREFIX is defined,
+	#      so just omit it for testing purposes.
+	#
+	#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's
+	#      sake, skip it when parsing normal.
+	sed \
+		-e 's/elapsed:[0-9]*\.[0-9][0-9]*\([eE][-+]\{0,1\}[0-9][0-9]*\)\{0,1\}/elapsed:_TIME_/g' \
+		-e "s/^start '[^']*' \(.*\)/start _EXE_ \1/" \
+		-e 's/^start [^ ][^ ]* \(.*\)/start _EXE_ \1/' \
+		-e '/^cmd_path/d' \
+		-e '/^cmd_ancestry/d'
+}
+
 test_expect_success 'normal stream, return code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '
 test_expect_success 'normal stream, return code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 1
@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '
 	test_when_finished "rm -r traces actual expect" &&
 	mkdir traces &&
 	GIT_TRACE2="$(pwd)/traces" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <"$(ls traces/*)" >actual &&
+	scrub_normal <"$(ls traces/*)" >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '
 test_expect_success 'normal stream, exit code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 0
@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '
 test_expect_success 'normal stream, exit code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 1
@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '
 test_expect_success 'normal stream, error event' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\''
@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '
 test_expect_success 'BUG messages are written to trace2' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 007bug &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 007bug
@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 008bug
@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 009bug_BUG
@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 010bug_BUG
@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '
 	test_config_global trace2.normalBrief 1 &&
 	test_config_global trace2.normalTarget "$(pwd)/trace.normal" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '
 	mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" &&
 	test_config_global include.path "$(pwd)/real.gitconfig" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl
deleted file mode 100644
index 7cc4de392a0..00000000000
--- a/t/t0210/scrub_normal.perl
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/perl
-#
-# Scrub the variable fields from the normal trace2 output to
-# make testing easier.
-
-use strict;
-use warnings;
-
-my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?';
-
-# This code assumes that the trace2 data was written with bare
-# turned on (which omits the "<clock> <file>:<line>" prefix.
-
-while (<>) {
-    # Various messages include an elapsed time in the middle
-    # of the message.  Replace the time with a placeholder to
-    # simplify our HEREDOC in the test script.
-    s/elapsed:$float/elapsed:_TIME_/g;
-
-    my $line = $_;
-
-    # we expect:
-    #    start <argv0> [<argv1> [<argv2> [...]]]
-    #
-    # where argv0 might be a relative or absolute path, with
-    # or without quotes, and platform dependent.  Replace argv0
-    # with a token for HEREDOC matching in the test script.
-
-    if ($line =~ m/^start/) {
-	$line =~ /^start\s+(.*)/;
-	my $argv = $1;
-	$argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/;
-	my $argv_0 = $1;
-	my $argv_rest = $2;
-
-	print "start _EXE_ $argv_rest\n";
-    }
-    elsif ($line =~ m/^cmd_path/) {
-	# Likewise, the 'cmd_path' message breaks out argv[0].
-	#
-	# This line is only emitted when RUNTIME_PREFIX is defined,
-	# so just omit it for testing purposes.
-	# print "cmd_path _EXE_\n";
-    }
-    elsif ($line =~ m/^cmd_ancestry/) {
-	# 'cmd_ancestry' is not implemented everywhere, so for portability's
-	# sake, skip it when parsing normal.
-	#
-	# print "$line";
-    }
-    else {
-	print "$line";
-    }
-}

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 19/20] t5316: refactor `max_chain()` to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (17 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-20  9:35 ` [PATCH 20/20] t5703: refactor test " Patrick Steinhardt
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

The `max_chain()` helper function is used to extract the maximum delta
chain of a packfile as printed by git-index-pack(1). The script uses
Perl to extract that data, but it can be trivially refactored to use
awk(1) instead.

Refactor the helper accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5316-pack-delta-depth.sh | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index cd947b5a5ef..defaa06d650 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '
 
 max_chain() {
 	git index-pack --verify-stat-only "$1" >output &&
-	perl -lne '
-	  BEGIN { $len = 0 }
-	  /chain length = (\d+)/ and $len = $1;
-	  END { print $len }
-	' output
+	awk '
+		BEGIN { len=0 }
+		/chain length = [0-9]+:/{ len=$4 }
+		END { print len }
+	' <output | tr -d ':'
 }
 
 # Note that this whole setup is pretty reliant on the current
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
+test_expect_success 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
+test_expect_success '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
+test_expect_success '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
+test_expect_success 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 20/20] t5703: refactor test to not depend on Perl
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (18 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
@ 2025-03-20  9:35 ` Patrick Steinhardt
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-20  9:35 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

We use Perl due to two different reasons in t5703:

  - To filter advertised capabilities.

  - To set up a CGI script with HTTPD.

Refactor the first category to use `test_grep` instead. Refactoring the
second category would be a bit more involved, so instead we add the
PERL_TEST_HELPERS prerequisite to those individual tests now.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index ac7266126a0..1ab3191d72d 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
-	test_done
-fi
-
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '
 
 test_expect_success 'config controls ref-in-want advertisement' '
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant false &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant true &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_file_not_empty out.filter
+	test_grep "ref-in-want" out
 '
 
 test_expect_success 'invalid want-ref line' '
@@ -486,7 +477,7 @@ inconsistency () {
 	EOF
 }
 
-test_expect_success 'server is initially ahead - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
 	test_grep "fatal: remote error: upload-pack: not our ref" err
 '
 
-test_expect_success 'server is initially ahead - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server loses a ref - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH 01/20] t: skip chain lint when PERL_PATH is unset
  2025-03-20  9:35 ` [PATCH 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
@ 2025-03-20 18:36   ` Eric Sunshine
  0 siblings, 0 replies; 121+ messages in thread
From: Eric Sunshine @ 2025-03-20 18:36 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 5:35 AM Patrick Steinhardt <ps@pks.im> wrote:
> Our chainlint scripts verify that test files have proper '&&' chains.

It's just a single script, so: s/scripts verify/script verifies/

> These scripts are written in Perl and are executed for every test file

s/These scripts/This script/
s/are/is/g

> before executing the test logic itself.
>
> In subsequent commits we're about to refactor our test suite so that
> Perl becomes an optional dependency, only. And while it is already
> possible to disable this linter, developers that don't have Perl
> available at all would always have to disable the linter manually, which
> is rather cumbersome.
>
> Disable the chain linter automatically in case PERL_PATH isn't set to
> make this a bit less annoying. Bail out with an error in case the
> developer has asked explicitly for the chain linter.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>

Not worth a reroll, of course.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-20  9:35 ` [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-03-20 18:55   ` Eric Sunshine
  2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Eric Sunshine @ 2025-03-20 18:55 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:
> [...]
> Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
> that require Perl. This prerequisite is explicitly different than the
> preexisting PERL prerequisite:
> [...]
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
> @@ -5,6 +5,12 @@ test_description=check-ignore
> +if ! test_have_prereq PERL_TEST_HELPERS
> +then
> +       skip_all='skipping ignores tests; Perl not available'
> +       test_done
> +fi
> diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
> @@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> +if ! test_have_prereq PERL_TEST_HELPERS
> +then
> +       skip_all='skipping ignores tests; Perl not available'
> +       test_done
> +fi

This message seems to have been copy/pasted. Should it be instead
"skipping apply-binary tests; Perl not available"?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 12/20] t: refactor tests depending on Perl to print data
  2025-03-20  9:35 ` [PATCH 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-03-20 19:33   ` Eric Sunshine
  2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Eric Sunshine @ 2025-03-20 19:33 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:
> A bunch of tests rely on Perl to print data in various different ways.
> These usages fall into the following categories:
>
>   - Print data conditionally by matching patterns. These usecases can be
>     converted to use awk(1) rather easily.
>
>   - Print data repeatedly. These usecases can typically be converted to
>     use a combination of `test-tool genzeros` and sed(1).
>
>   - Print data in reverse. These usecases can be converted to use
>     awk(1).
>
> Refactor the tests accordingly so that we can drop a couple of
> PERL_TEST_HELPERS prerequisites.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
> @@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
> -test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
> +test_expect_success 'basic: can write large commit message' '
>         test_when_finished "rm -rf repo" &&
>         git init repo &&
> -       perl -e "
> -               print \"this is a long commit message\" x 50000
> -       " >commit-msg &&
> +
> +       awk "BEGIN { for (i = 0; i < 50000; i++) print \"this is a long commit message\" }" >commit-msg &&
>         git -C repo commit --allow-empty --file=../commit-msg
>  '

The original Perl version emitted the entire message as a single-line,
whereas the awk replacement emits 50,000 lines. Was the intent of the
original specifically to check whether it handled an extremely long
line correctly, or was it merely checking whether an overall very
lengthy content was handled correctly? If the former, then this
semantic change is inconsistent with what this test wants to be
checking; if the latter, then this semantic change is harmless.

Also, it is possible to do this entirely in shell without running an
external program (assuming `test` and `printf` are builtins):

  i=0 &&
  while test $i -lt 50000
  do
    echo "this is a long commit message" &&
    i=$(($i+1)) ||
    return 1
  done &&

> diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
> @@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
>                 echo object-format=$(test_oid algo) &&
>                 echo 0001 &&
> -               perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
> +               awk "{
> +                       for (i = 1; i <= 65536; i++)
> +                               print \"ref-prefix refs/heads/\", \$i
> +               }" &&
>                 echo 0000

In this one, the Perl version emitted 65,536 lines, so the awk version
is consistent with that. Okay.

This could also be done purely in shell without using awk.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-20  9:35 ` [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-03-20 19:37   ` Eric Sunshine
  2025-03-24 12:46     ` Patrick Steinhardt
  2025-03-24 16:16   ` Phillip Wood
  1 sibling, 1 reply; 121+ messages in thread
From: Eric Sunshine @ 2025-03-20 19:37 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> We have a couple of tests that depend on Perl for textconv scripts.
> Refactor these tests to instead be implemented via shell utilities so
> that we can drop a couple of PERL_TEST_HELPERS prerequisites.
>
> Note that not all of the conversions are a one-to-one equivalent to the
> previous textconv scripts. But that's not really needed in the first
> place: we only care that the textconv script does something, and that
> can be verified trivially without having a full-blown invocation of
> hexdump. So at times, the implementation of the textconv scripts is
> reduced to their bare minimum.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> +test_expect_success 'rewrite diff respects textconv' '
>         git diff -B >diff &&
> -       grep "dissimilarity index" diff &&
> -       grep "^-61" diff &&
> -       grep "^-0" diff
> +       test_grep "dissimilarity index" diff &&
> +       test_grep "^-3d 0a 00" diff &&
> +       test_grep "^+3d 0a 01" diff
>  '

This change seems unrelated to the stated purpose (`textconv`) of this patch(?).

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-03-20  9:35 ` [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
@ 2025-03-20 19:41   ` Eric Sunshine
  2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Eric Sunshine @ 2025-03-20 19:41 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> The `name_from_description()` test helper uses Perl to munge a given
> description and convert it into a name. Refactor it to instead use a
> combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
> prerequisites in users of this library.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
> @@ -109,13 +109,12 @@ check_output () {
>  # All alphanums translated into -'s which are then compressed and stripped
>  # from front and back.
>  name_from_description () {
> -       perl -pe '
> -               s/[^A-Za-z0-9.]/-/g;
> -               s/-+/-/g;
> -               s/-$//;
> -               s/^-//;
> -               y/A-Z/a-z/;
> -       '
> +       sed \
> +               -e 's/[^A-Za-z0-9.]/-/g' \
> +               -e 's/--*/-/g' \
> +               -e 's/-$//' \
> +               -e 's/^-//' |
> +       tr 'A-Z' 'a-z'
>  }

Can't you just use sed's `y//` function directly instead of having to
separately invoke a `tr` command?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 02/20] t: refactor environment sanitization to not use Perl
  2025-03-20  9:35 ` [PATCH 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
@ 2025-03-21  9:52   ` Karthik Nayak
  0 siblings, 0 replies; 121+ messages in thread
From: Karthik Nayak @ 2025-03-21  9:52 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin

[-- Attachment #1: Type: text/plain, Size: 2231 bytes --]

Patrick Steinhardt <ps@pks.im> writes:

> Before executing tests we first sanitize the environment. Part of the
> sanitization is to unset a couple of environment variables that we know
> will change the behaviour of Git. This is done with a small Perl script,
> which has the consequence that having a Perl interpreter available is a
> strict requirement for running our unit tests.
>
> The logic itself isn't particularly involved: we simply unset every
> environment variable whose key starts with 'GIT_', but then explicitly
> allow a subset of these.
>
> Refactor the logic to instead use sed(1) so that it becomes possible to
> execute our tests without Perl.
>
> Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  t/test-lib.sh | 32 ++++++++++++++------------------
>  1 file changed, 14 insertions(+), 18 deletions(-)
>
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 1ce3b32fcac..a62699d6c79 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -499,24 +499,20 @@ EDITOR=:
>  # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
>  # deriving from the command substitution clustered with the other
>  # ones.
> -unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
> -	my @env = keys %ENV;
> -	my $ok = join("|", qw(
> -		TRACE
> -		DEBUG
> -		TEST
> -		.*_TEST
> -		PROVE
> -		VALGRIND
> -		UNZIP
> -		PERF_
> -		CURL_VERBOSE
> -		TRACE_CURL
> -		BUILD_DIR
> -	));
> -	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
> -	print join("\n", @vars);
> -')
> +unset VISUAL EMAIL LANGUAGE $(env | sed -n \
> +	-e '/^GIT_TRACE/d' \
> +	-e '/^GIT_DEBUG/d' \
> +	-e '/^GIT_TEST/d' \
> +	-e '/^GIT_.*_TEST/d' \
> +	-e '/^GIT_PROVE/d' \
> +	-e '/^GIT_VALGRIND/d' \
> +	-e '/^GIT_UNZIP/d' \
> +	-e '/^GIT_PERF_/d' \
> +	-e '/^GIT_CURL_VERBOSE/d' \
> +	-e '/^GIT_TRACE_CURL/d' \
> +	-e '/^GIT_BUILD_DIR/d' \

So we delete all of the following from the stream of env.

> +	-e 's/^\(GIT_[^=]*\)=.*/\1/p'

But any other `GIT_*` env variable is printed to be `unset`. Ok makes
sense. This is much more readable than the perl version!

> +)
>  unset XDG_CACHE_HOME
>  unset XDG_CONFIG_HOME
>  unset GITPERLLIB
>
> --
> 2.49.0.472.ge94155a9ec.dirty

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 04/20] t: adapt `test_copy_bytes()` to not use Perl
  2025-03-20  9:35 ` [PATCH 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
@ 2025-03-21  9:56   ` Karthik Nayak
  0 siblings, 0 replies; 121+ messages in thread
From: Karthik Nayak @ 2025-03-21  9:56 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin

[-- Attachment #1: Type: text/plain, Size: 1186 bytes --]

Patrick Steinhardt <ps@pks.im> writes:

> The `test_copy_bytes()` helper function copies up to N bytes from stdin
> to stdout. This is implemented using Perl, but it can be trivially
> adapted to instead use dd(1).
>
> Refactor the helper accordingly, which allows a bunch of tests to pass
> when Perl is not available.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  t/test-lib-functions.sh | 12 +-----------
>  1 file changed, 1 insertion(+), 11 deletions(-)
>
> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
> index 377f08a1428..c4b4d3a4c7f 100644
> --- a/t/test-lib-functions.sh
> +++ b/t/test-lib-functions.sh
> @@ -1640,17 +1640,7 @@ test_match_signal () {
>
>  # Read up to "$1" bytes (or to EOF) from stdin and write them to stdout.
>  test_copy_bytes () {
> -	perl -e '
> -		my $len = $ARGV[1];
> -		while ($len > 0) {
> -			my $s;
> -			my $nread = sysread(STDIN, $s, $len);
> -			die "cannot read: $!" unless defined($nread);
> -			last unless $nread;
> -			print $s;
> -			$len -= $nread;
> -		}
> -	' - "$1"
> +	dd ibs=1 count="$1" 2>/dev/null
>  }
>

Really nice!

>  # run "$@" inside a non-git directory
>
> --
> 2.49.0.472.ge94155a9ec.dirty

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-20 19:37   ` Eric Sunshine
@ 2025-03-24 12:46     ` Patrick Steinhardt
  2025-03-24 16:07       ` Eric Sunshine
  0 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-24 12:46 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:
> On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> > We have a couple of tests that depend on Perl for textconv scripts.
> > Refactor these tests to instead be implemented via shell utilities so
> > that we can drop a couple of PERL_TEST_HELPERS prerequisites.
> >
> > Note that not all of the conversions are a one-to-one equivalent to the
> > previous textconv scripts. But that's not really needed in the first
> > place: we only care that the textconv script does something, and that
> > can be verified trivially without having a full-blown invocation of
> > hexdump. So at times, the implementation of the textconv scripts is
> > reduced to their bare minimum.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> > +test_expect_success 'rewrite diff respects textconv' '
> >         git diff -B >diff &&
> > -       grep "dissimilarity index" diff &&
> > -       grep "^-61" diff &&
> > -       grep "^-0" diff
> > +       test_grep "dissimilarity index" diff &&
> > +       test_grep "^-3d 0a 00" diff &&
> > +       test_grep "^+3d 0a 01" diff
> >  '
> 
> This change seems unrelated to the stated purpose (`textconv`) of this patch(?).

Not quite. The test previously didn't run because it depends on the
Perl-based textconv script. Now that this textconv script was adapted
to use shell scripting instead it can run, but as explained in the
commit message the output of the textconv script changed. We don't
really care for the exact output at all, we only care that textconv did
its thing. But we do have to adapt the test accordingly.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-20 18:55   ` Eric Sunshine
@ 2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-24 12:46 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 02:55:34PM -0400, Eric Sunshine wrote:
> On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:
> > [...]
> > Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
> > that require Perl. This prerequisite is explicitly different than the
> > preexisting PERL prerequisite:
> > [...]
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> > diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
> > @@ -5,6 +5,12 @@ test_description=check-ignore
> > +if ! test_have_prereq PERL_TEST_HELPERS
> > +then
> > +       skip_all='skipping ignores tests; Perl not available'
> > +       test_done
> > +fi
> > diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
> > @@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> > +if ! test_have_prereq PERL_TEST_HELPERS
> > +then
> > +       skip_all='skipping ignores tests; Perl not available'
> > +       test_done
> > +fi
> 
> This message seems to have been copy/pasted. Should it be instead
> "skipping apply-binary tests; Perl not available"?

Yup, good catch!

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-03-20 19:41   ` Eric Sunshine
@ 2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-24 12:46 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 03:41:11PM -0400, Eric Sunshine wrote:
> On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> > The `name_from_description()` test helper uses Perl to munge a given
> > description and convert it into a name. Refactor it to instead use a
> > combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
> > prerequisites in users of this library.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> > diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
> > @@ -109,13 +109,12 @@ check_output () {
> >  # All alphanums translated into -'s which are then compressed and stripped
> >  # from front and back.
> >  name_from_description () {
> > -       perl -pe '
> > -               s/[^A-Za-z0-9.]/-/g;
> > -               s/-+/-/g;
> > -               s/-$//;
> > -               s/^-//;
> > -               y/A-Z/a-z/;
> > -       '
> > +       sed \
> > +               -e 's/[^A-Za-z0-9.]/-/g' \
> > +               -e 's/--*/-/g' \
> > +               -e 's/-$//' \
> > +               -e 's/^-//' |
> > +       tr 'A-Z' 'a-z'
> >  }
> 
> Can't you just use sed's `y//` function directly instead of having to
> separately invoke a `tr` command?

Ah, of course, will change!

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 12/20] t: refactor tests depending on Perl to print data
  2025-03-20 19:33   ` Eric Sunshine
@ 2025-03-24 12:46     ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-24 12:46 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Johannes Schindelin

On Thu, Mar 20, 2025 at 03:33:44PM -0400, Eric Sunshine wrote:
> On Thu, Mar 20, 2025 at 5:36 AM Patrick Steinhardt <ps@pks.im> wrote:
> > A bunch of tests rely on Perl to print data in various different ways.
> > These usages fall into the following categories:
> >
> >   - Print data conditionally by matching patterns. These usecases can be
> >     converted to use awk(1) rather easily.
> >
> >   - Print data repeatedly. These usecases can typically be converted to
> >     use a combination of `test-tool genzeros` and sed(1).
> >
> >   - Print data in reverse. These usecases can be converted to use
> >     awk(1).
> >
> > Refactor the tests accordingly so that we can drop a couple of
> > PERL_TEST_HELPERS prerequisites.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> > diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
> > @@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
> > -test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
> > +test_expect_success 'basic: can write large commit message' '
> >         test_when_finished "rm -rf repo" &&
> >         git init repo &&
> > -       perl -e "
> > -               print \"this is a long commit message\" x 50000
> > -       " >commit-msg &&
> > +
> > +       awk "BEGIN { for (i = 0; i < 50000; i++) print \"this is a long commit message\" }" >commit-msg &&
> >         git -C repo commit --allow-empty --file=../commit-msg
> >  '
> 
> The original Perl version emitted the entire message as a single-line,
> whereas the awk replacement emits 50,000 lines. Was the intent of the
> original specifically to check whether it handled an extremely long
> line correctly, or was it merely checking whether an overall very
> lengthy content was handled correctly? If the former, then this
> semantic change is inconsistent with what this test wants to be
> checking; if the latter, then this semantic change is harmless.

It really only wants to check for a big message, the exact format does
not matter at all. So in theory, we could even adapt this to use
`test-tool genzeros | tr "\000" "a"` or something like that, but I
didn't want to argue why that change is okay. The fact that we now have
a newline was unintentional.

> Also, it is possible to do this entirely in shell without running an
> external program (assuming `test` and `printf` are builtins):
> 
>   i=0 &&
>   while test $i -lt 50000
>   do
>     echo "this is a long commit message" &&
>     i=$(($i+1)) ||
>     return 1
>   done &&

True, but it's significantly slower. We already use awk in many places,
so we can just as well use it here. I'll adapt the refactoring to drop
the newlines.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-24 12:46     ` Patrick Steinhardt
@ 2025-03-24 16:07       ` Eric Sunshine
  2025-03-25 12:42         ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Eric Sunshine @ 2025-03-24 16:07 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Johannes Schindelin

On Mon, Mar 24, 2025 at 8:46 AM Patrick Steinhardt <ps@pks.im> wrote:
> On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:
> > On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> > > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> > > +test_expect_success 'rewrite diff respects textconv' '
> > >         git diff -B >diff &&
> > > -       grep "dissimilarity index" diff &&
> > > -       grep "^-61" diff &&
> > > -       grep "^-0" diff
> > > +       test_grep "dissimilarity index" diff &&
> > > +       test_grep "^-3d 0a 00" diff &&
> > > +       test_grep "^+3d 0a 01" diff
> > >  '
> >
> > This change seems unrelated to the stated purpose (`textconv`) of this patch(?).
>
> Not quite. The test previously didn't run because it depends on the
> Perl-based textconv script. Now that this textconv script was adapted
> to use shell scripting instead it can run, but as explained in the
> commit message the output of the textconv script changed. We don't
> really care for the exact output at all, we only care that textconv did
> its thing. But we do have to adapt the test accordingly.

Okay, I see that now that I have read your response and examined the
change more closely. The unrelated `grep` to `test_grep` change
visually overwhelms the diff, so much so that I overlooked the other
smaller necessary changes. Perhaps it would make sense to mention the
unrelated change in the commit message but is not itself worth a
reroll.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-20  9:35 ` [PATCH 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-03-24 16:16   ` Phillip Wood
  0 siblings, 0 replies; 121+ messages in thread
From: Phillip Wood @ 2025-03-24 16:16 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin

Hi Patrick

On 20/03/2025 09:35, Patrick Steinhardt wrote:
> We have a bunch of tests that use Perl to perform substitution via the
> "s/" operator. These usecases can be trivially replaced with sed(1).
> 
> Refactor the tests accordingly so that we can drop a couple of
> PERL_TEST_HELPERS prerequisites.

Nice

>   broken_c_unquote () {
> -	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
> +	<"$1" sed -e 's/^"//' -e 's/\\//' -e 's/"$//' | tr '\n' '\0'
>   }
>   
>   broken_c_unquote_verbose () {
> -	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
> +	<"$1" sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' | tr ':\t\n' '\000'

I found the redirection here rather strange - we can just do 'sed -e ... 
"$1" | tr ...'. The same applies to all the other sed commands that have 
their stdin redirected from a file.

Best Wishes

Phillip

>   }
>   
>   stderr_contains () {
> diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
> index a92a42990b1..db75998e35f 100755
> --- a/t/t4029-diff-trailing-space.sh
> +++ b/t/t4029-diff-trailing-space.sh
> @@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
>   EOF
>   exit 1
>   
> -test_expect_success PERL_TEST_HELPERS "$test_description" '
> +test_expect_success "$test_description" '
>   	printf "\nx\n" > f &&
>   	before=$(git hash-object f) &&
>   	before=$(git rev-parse --short $before) &&
> @@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
>   	git config --bool diff.suppressBlankEmpty true &&
>   	git diff f > actual &&
>   	test_cmp exp actual &&
> -	perl -i.bak -p -e "s/^\$/ /" exp &&
> +	sed "s/^\$/ /" <exp >exp.munged &&
> +	mv exp.munged exp &&
>   	git config --bool diff.suppressBlankEmpty false &&
>   	git diff f > actual &&
>   	test_cmp exp actual &&
> diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
> index 7fcca9ddad5..bacb93d014f 100755
> --- a/t/t4200-rerere.sh
> +++ b/t/t4200-rerere.sh
> @@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping rerere tests; Perl not available'
> -	test_done
> -fi
> -
>   test_expect_success 'setup' '
>   	cat >a1 <<-\EOF &&
>   	Some title
> @@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
>   	test_might_fail git config --unset rerere.enabled &&
>   	test_must_fail git merge first &&
>   
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1 &&
>   	grep "^=======\$" $rr/preimage &&
>   	! test -f $rr/postimage &&
> @@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
>   	git reset --hard &&
>   	test_must_fail git merge first &&
>   
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1 &&
>   	grep ^=======$ $rr/preimage
>   '
> @@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
>   	git config rerere.enabled true &&
>   	git reset --hard &&
>   	test_must_fail git merge first &&
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1
>   '
>   
> diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
> index ac5e370e1e4..07382797bbb 100755
> --- a/t/t5303-pack-corruption-resilience.sh
> +++ b/t/t5303-pack-corruption-resilience.sh
> @@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
>   	git cat-file blob $blob_3 > /dev/null
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
> +test_expect_success 'create corruption in data of first object' '
>   	create_new_pack &&
>   	git prune-packed &&
>   	chmod +w ${pack}.pack &&
> -	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
> +	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
> +	mv ${pack}.pack.munged ${pack}.pack &&
>   	test_must_fail git cat-file blob $blob_1 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_3 > /dev/null
> @@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
>   	git cat-file blob $blob_3 > /dev/null
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
> +test_expect_success 'create corruption in data of first delta' '
>   	create_new_pack &&
>   	git prune-packed &&
>   	chmod +w ${pack}.pack &&
> -	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
> +	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
> +	mv ${pack}.pack.munged ${pack}.pack &&
>   	git cat-file blob $blob_1 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_3 > /dev/null
> diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
> index 81987296235..9033d72b8c7 100755
> --- a/t/t5310-pack-bitmaps.sh
> +++ b/t/t5310-pack-bitmaps.sh
> @@ -395,7 +395,7 @@ test_bitmap_cases () {
>   		)
>   	'
>   
> -	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
> +	test_expect_success 'pack.preferBitmapTips' '
>   		git init repo &&
>   		test_when_finished "rm -fr repo" &&
>   		(
> @@ -421,7 +421,7 @@ test_bitmap_cases () {
>   
>   			# mark the commits which did not receive bitmaps as preferred,
>   			# and generate the bitmap again
> -			perl -pe "s{^}{create refs/tags/include/$. }" <before |
> +			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
>   				git update-ref --stdin &&
>   			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
>   
> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
> index 342d0423c92..d5c0d00114e 100755
> --- a/t/t5534-push-signed.sh
> +++ b/t/t5534-push-signed.sh
> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
>   	test_cmp expect dst/push-cert-status
>   '
>   
> -test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
> +test_expect_success GPG 'inconsistent push options in signed push not allowed' '
>   	# First, invoke receive-pack with dummy input to obtain its preamble.
>   	prepare_dst &&
>   	git -C dst config receive.certnonceseed sekrit &&
> @@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
>   	# Tweak the push output to make the push option outside the cert
>   	# different, then replay it on a fresh dst, checking that ff is not
>   	# deleted.
> -	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
> +	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
>   	prepare_dst &&
>   	git -C dst config receive.certnonceseed sekrit &&
>   	git -C dst config receive.advertisepushoptions 1 &&
> diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
> index 6131c361094..12329aab388 100755
> --- a/t/t6011-rev-list-with-bad-commit.sh
> +++ b/t/t6011-rev-list-with-bad-commit.sh
> @@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping rev-list with bad commit tests; Perl not available'
> -	test_done
> -fi
> -
>   # Note:
>   # - compression level is set to zero to make "corruptions" easier to perform
>   # - reflog is disabled to avoid extra references which would twart the test
> @@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
>      first_commit=$(git rev-parse HEAD~3)
>      '
>   
> -test_expect_success 'corrupt second commit object' \
> -   '
> -   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
> -   test_must_fail git fsck --full
> -   '
> +test_expect_success 'corrupt second commit object' '
> +	for p in .git/objects/pack/*.pack
> +	do
> +		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
> +		mv "$p.munged" "$p" ||
> +		return 1
> +	done &&
> +	test_must_fail git fsck --full
> +'
>   
>   test_expect_success 'rev-list should fail' '
>   	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
> diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
> index 14069600a2f..00b81d349b9 100755
> --- a/t/t7416-submodule-dash-url.sh
> +++ b/t/t7416-submodule-dash-url.sh
> @@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping submodule dash URL tests; Perl not available'
> -	test_done
> -fi
> -
>   test_expect_success 'setup' '
>   	git config --global protocol.file.allow always
>   '
> @@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
>   '
>   
>   test_expect_success 'remove ./ protection from .gitmodules url' '
> -	perl -i -pe "s{\./}{}" .gitmodules &&
> +	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
> +	mv .gitmodules.munged .gitmodules &&
>   	git commit -am "drop protection"
>   '
>   
> diff --git a/t/t7508-status.sh b/t/t7508-status.sh
> index 14c41b2cb7c..cdc1d6fcc78 100755
> --- a/t/t7508-status.sh
> +++ b/t/t7508-status.sh
> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
>   	test_cmp expect output
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
> +test_expect_success 'status -z implies porcelain' '
>   	git status --porcelain |
> -	perl -pe "s/\012/\000/g" >expect &&
> +	tr "\012" "\000" >expect &&
>   	git status -z >output &&
>   	test_cmp expect output
>   '
> diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
> index 5cb16872081..810dac18f56 100755
> --- a/t/t8006-blame-textconv.sh
> +++ b/t/t8006-blame-textconv.sh
> @@ -4,12 +4,6 @@ test_description='git blame textconv support'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping blame textconv tests; Perl not available'
> -	test_done
> -fi
> -
>   find_blame() {
>   	sed -e 's/^[^(]*//'
>   }
> @@ -17,7 +11,7 @@ find_blame() {
>   cat >helper <<'EOF'
>   #!/bin/sh
>   grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
> -"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
> +sed 's/^bin: /converted: /' <"$1"
>   EOF
>   chmod +x helper
>   
> diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
> index a9d38be997c..9afdb45b1cc 100755
> --- a/t/t9137-git-svn-dcommit-clobber-series.sh
> +++ b/t/t9137-git-svn-dcommit-clobber-series.sh
> @@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
>   	test -e file
>   	'
>   
> -test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
> +test_expect_success '(supposedly) non-conflicting change from SVN' '
>   	test x"$(sed -n -e 58p < file)" = x58 &&
>   	test x"$(sed -n -e 61p < file)" = x61 &&
>   	svn_cmd co "$svnrepo" tmp &&
>   	(cd tmp &&
> -		perl -i.bak -p -e "s/^58$/5588/" file &&
> -		perl -i.bak -p -e "s/^61$/6611/" file &&
> +		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
> +		mv file.munged file &&
>   		poke file &&
>   		test x"$(sed -n -e 58p < file)" = x5588 &&
>   		test x"$(sed -n -e 61p < file)" = x6611 &&
> @@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
>   	git commit -m bye-life life
>   	"
>   
> -test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
> +test_expect_success 'change file but in unrelated area' "
>   	test x\"\$(sed -n -e 4p < file)\" = x4 &&
>   	test x\"\$(sed -n -e 7p < file)\" = x7 &&
> -	perl -i.bak -p -e 's/^4\$/4444/' file &&
> -	perl -i.bak -p -e 's/^7\$/7777/' file &&
> +	sed -e 's/^4\$/4444/' \
> +	    -e 's/^7\$/7777/' \
> +		<file >file.munged &&
> +	mv file.munged file &&
>   	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
>   	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
>   	git commit -m '4 => 4444, 7 => 7777' file &&
> 


^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-20  9:35 ` [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
  2025-03-20 19:37   ` Eric Sunshine
@ 2025-03-24 16:16   ` Phillip Wood
  2025-03-25 12:43     ` Patrick Steinhardt
  1 sibling, 1 reply; 121+ messages in thread
From: Phillip Wood @ 2025-03-24 16:16 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin

Hi Patrick

On 20/03/2025 09:35, Patrick Steinhardt wrote:
> We have a couple of tests that depend on Perl for textconv scripts.
> Refactor these tests to instead be implemented via shell utilities so
> that we can drop a couple of PERL_TEST_HELPERS prerequisites.
> 
> Note that not all of the conversions are a one-to-one equivalent to the
> previous textconv scripts. But that's not really needed in the first
> place: we only care that the textconv script does something, and that
> can be verified trivially without having a full-blown invocation of
> hexdump. So at times, the implementation of the textconv scripts is
> reduced to their bare minimum.
 > > -cat >hexdump <<'EOF'
> -#!/bin/sh
> -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> -EOF
> -chmod +x hexdump
> -
>   test_expect_success 'setup binary file with history' '
> +	write_script hexdump <<-\EOF &&
> +	tr "\000\001" "01" <"$1"
I guess it is fine just to handle the characters we expect at the moment 
(is that what the second paragraph of the commit message is referring 
to?), but the script it was more tolerant of future changes to the test 
data. We could always just use 'test-tool hexdump' here like the tests 
below but it is probably not worth a re-roll on its own.

Overall this series looks like a useful improvement.

Thanks

Phillip

> +	EOF
>   	test_commit --printf one file "\\0\\n" &&
>   	test_commit --printf --append two file "\\01\\n"
>   '
> diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
> index cbe50b15772..15e012ccc7c 100755
> --- a/t/t4031-diff-rewrite-binary.sh
> +++ b/t/t4031-diff-rewrite-binary.sh
> @@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
>   	grep " rewrite file" diff
>   '
>   
> -{
> -	echo "#!$SHELL_PATH"
> -	cat <<'EOF'
> -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> -EOF
> -} >dump
> -chmod +x dump
> -
>   test_expect_success 'setup textconv' '
> +	write_script dump <<-\EOF &&
> +	test-tool hexdump <"$1"
> +	EOF
>   	echo file diff=foo >.gitattributes &&
>   	git config diff.foo.textconv "\"$(pwd)\""/dump
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> +test_expect_success 'rewrite diff respects textconv' '
>   	git diff -B >diff &&
> -	grep "dissimilarity index" diff &&
> -	grep "^-61" diff &&
> -	grep "^-0" diff
> +	test_grep "dissimilarity index" diff &&
> +	test_grep "^-3d 0a 00" diff &&
> +	test_grep "^+3d 0a 01" diff
>   '
>   
>   test_done
> diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
> index b2730d200c8..3bd91da9707 100755
> --- a/t/t7815-grep-binary.sh
> +++ b/t/t7815-grep-binary.sh
> @@ -4,12 +4,6 @@ test_description='git grep in binary files'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping grep binary tests; Perl not available'
> -	test_done
> -fi
> -
>   test_expect_success 'setup' "
>   	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
>   	git add a &&
> @@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
>   	test_cmp expect actual
>   '
>   
> -cat >nul_to_q_textconv <<'EOF'
> -#!/bin/sh
> -"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
> -EOF
> -chmod +x nul_to_q_textconv
> -
>   test_expect_success 'setup textconv filters' '
> +	write_script nul_to_q_textconv <<-\EOF &&
> +	tr "\000" "Q" <"$1"
> +	EOF
>   	echo a diff=foo >.gitattributes &&
>   	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
>   '
> 


^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-24 16:07       ` Eric Sunshine
@ 2025-03-25 12:42         ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 12:42 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Johannes Schindelin

On Mon, Mar 24, 2025 at 12:07:52PM -0400, Eric Sunshine wrote:
> On Mon, Mar 24, 2025 at 8:46 AM Patrick Steinhardt <ps@pks.im> wrote:
> > On Thu, Mar 20, 2025 at 03:37:08PM -0400, Eric Sunshine wrote:
> > > On Thu, Mar 20, 2025 at 5:37 AM Patrick Steinhardt <ps@pks.im> wrote:
> > > > -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> > > > +test_expect_success 'rewrite diff respects textconv' '
> > > >         git diff -B >diff &&
> > > > -       grep "dissimilarity index" diff &&
> > > > -       grep "^-61" diff &&
> > > > -       grep "^-0" diff
> > > > +       test_grep "dissimilarity index" diff &&
> > > > +       test_grep "^-3d 0a 00" diff &&
> > > > +       test_grep "^+3d 0a 01" diff
> > > >  '
> > >
> > > This change seems unrelated to the stated purpose (`textconv`) of this patch(?).
> >
> > Not quite. The test previously didn't run because it depends on the
> > Perl-based textconv script. Now that this textconv script was adapted
> > to use shell scripting instead it can run, but as explained in the
> > commit message the output of the textconv script changed. We don't
> > really care for the exact output at all, we only care that textconv did
> > its thing. But we do have to adapt the test accordingly.
> 
> Okay, I see that now that I have read your response and examined the
> change more closely. The unrelated `grep` to `test_grep` change
> visually overwhelms the diff, so much so that I overlooked the other
> smaller necessary changes. Perhaps it would make sense to mention the
> unrelated change in the commit message but is not itself worth a
> reroll.

I already tried to describe this in the commit message, but obviously I
seem to have failed :) I'll add another sentence to mention that tests
have to be adapted accordingly.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-24 16:16   ` Phillip Wood
@ 2025-03-25 12:43     ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 12:43 UTC (permalink / raw)
  To: phillip.wood; +Cc: git, Johannes Schindelin

On Mon, Mar 24, 2025 at 04:16:22PM +0000, Phillip Wood wrote:
> Hi Patrick
> 
> On 20/03/2025 09:35, Patrick Steinhardt wrote:
> > We have a couple of tests that depend on Perl for textconv scripts.
> > Refactor these tests to instead be implemented via shell utilities so
> > that we can drop a couple of PERL_TEST_HELPERS prerequisites.
> > 
> > Note that not all of the conversions are a one-to-one equivalent to the
> > previous textconv scripts. But that's not really needed in the first
> > place: we only care that the textconv script does something, and that
> > can be verified trivially without having a full-blown invocation of
> > hexdump. So at times, the implementation of the textconv scripts is
> > reduced to their bare minimum.
> > > -cat >hexdump <<'EOF'
> > -#!/bin/sh
> > -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> > -EOF
> > -chmod +x hexdump
> > -
> >   test_expect_success 'setup binary file with history' '
> > +	write_script hexdump <<-\EOF &&
> > +	tr "\000\001" "01" <"$1"
> I guess it is fine just to handle the characters we expect at the moment (is
> that what the second paragraph of the commit message is referring to?), but
> the script it was more tolerant of future changes to the test data. We could
> always just use 'test-tool hexdump' here like the tests below but it is
> probably not worth a re-roll on its own.

That was my first version, but it required a bunch of changes to tests
all over the place. So I decided to simplify this test suite to do the
bare minimum.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (19 preceding siblings ...)
  2025-03-20  9:35 ` [PATCH 20/20] t5703: refactor test " Patrick Steinhardt
@ 2025-03-25 13:14 ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
                     ` (19 more replies)
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
  22 siblings, 20 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi,

while Git was initially building on Perl quite a lot, the significance
of Perl has been dwindling over the years as more and more functionality
was converted into C builtins. Nowadays, an installation with Perl-based
features disabled is almost fully functional, only a handful of features
remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these features really are critical for day-to-day usage of Git,
and most users probably wouldn't even notice if those features were not
installed. Perl is thus very much optional nowadays.

There is one big exception though: it is impossible to run our test
suite without a Perl interpreter, so it is not easily possible to verify
that a Perl-less installation actually works as expected. For most of
the part though our test suite doesn't use all that much Perl, either.
It is present in a couple of critical paths, but those are easy to adapt
to not use Perl anymore.

This is exactly what this patch series does: it refactors a couple of
central parts in our test suite to not use Perl anymore so that it
becomes possible to run most of our tests entirely without Perl. Tests
that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq
so that they only execute when a Perl interpreter is available.

With this patch series, 30342 out of 31358 tests pass, which is around
97% of our tests.

Changes in v2:
  - Improve a couple of conversions based on feedback.
  - Clarify the commit message of the textconv conversion.
  - Fix a copy-paste error when it comes to skipping tests in t4103.
  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (20):
      t: skip chain lint when PERL_PATH is unset
      t: refactor environment sanitization to not use Perl
      t: adapt character translation helpers to not use Perl
      t: adapt `test_copy_bytes()` to not use Perl
      t: adapt `test_readlink()` to not use Perl
      t: introduce PERL_TEST_HELPERS prerequisite
      t: adapt existing PERL prerequisites
      meson: stop requiring Perl when tests are enabled
      Makefile: stop requiring Perl when running tests
      t: refactor tests depending on Perl transliteration operator
      t: refactor tests depending on Perl substitution operator
      t: refactor tests depending on Perl to print data
      t: refactor tests depending on Perl for textconv scripts
      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
      t/lib-t6000: refactor `name_from_description()` to not depend on Perl
      t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
      t0021: refactor `generate_random_characters()` to not depend on Perl
      t0210: refactor trace2 scrubbing to not use Perl
      t5316: refactor `max_chain()` to not depend on Perl
      t5703: refactor test to not depend on Perl

 meson.build                               |  2 +-
 t/Makefile                                | 16 +++++++--
 t/helper/test-path-utils.c                | 13 ++++++++
 t/helper/test-sha1.sh                     |  4 +--
 t/lib-diff.sh                             |  4 +--
 t/lib-gpg.sh                              |  6 +---
 t/lib-httpd.sh                            |  2 +-
 t/lib-httpd/apache.conf                   |  6 ++--
 t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------
 t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++
 t/lib-t6000.sh                            | 13 ++++----
 t/t0008-ignores.sh                        |  4 +--
 t/t0021-conversion.sh                     | 13 ++++----
 t/t0090-cache-tree.sh                     |  4 +--
 t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------
 t/t0210/scrub_normal.perl                 | 54 ------------------------------
 t/t0211-trace2-perf.sh                    |  6 ++++
 t/t0610-reftable-basics.sh                |  5 ++-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       | 16 +++++----
 t/t1007-hash-object.sh                    |  6 ++--
 t/t1010-mktree.sh                         |  4 +--
 t/t1450-fsck.sh                           |  6 ++--
 t/t3300-funny-names.sh                    |  6 ++--
 t/t4013-diff-various.sh                   |  6 ++++
 t/t4014-format-patch.sh                   | 30 ++++++++---------
 t/t4020-diff-external.sh                  |  2 +-
 t/t4029-diff-trailing-space.sh            |  3 +-
 t/t4030-diff-textconv.sh                  |  9 ++---
 t/t4031-diff-rewrite-binary.sh            | 17 ++++------
 t/t4058-diff-duplicates.sh                |  6 ++++
 t/t4103-apply-binary.sh                   |  6 ++--
 t/t4116-apply-reverse.sh                  |  4 +--
 t/t4150-am.sh                             |  8 ++---
 t/t4200-rerere.sh                         |  8 ++---
 t/t4205-log-pretty-formats.sh             |  6 ++--
 t/t4216-log-bloom.sh                      |  8 ++---
 t/t5004-archive-corner-cases.sh           |  6 ++++
 t/t5300-pack-object.sh                    | 10 +++---
 t/t5303-pack-corruption-resilience.sh     |  6 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               | 10 +++---
 t/t5318-commit-graph.sh                   | 12 +++----
 t/t5319-multi-pack-index.sh               | 16 ++++-----
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  4 +--
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  2 +-
 t/t5503-tagfollow.sh                      |  6 ++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++
 t/t5532-fetch-proxy.sh                    |  6 ++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  | 15 ++++-----
 t/t5551-http-fetch-smart.sh               |  7 ++++
 t/t5562-http-backend-content-length.sh    |  6 ++++
 t/t5601-clone.sh                          |  4 +--
 t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------
 t/t5701-git-serve.sh                      |  5 ++-
 t/t5702-protocol-v2.sh                    | 21 +++++++-----
 t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------
 t/t5710-promisor-remote-capability.sh     |  6 ++++
 t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---
 t/t6013-rev-list-reverse-parents.sh       | 10 +++---
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++
 t/t6115-rev-list-du.sh                    |  2 +-
 t/t6300-for-each-ref.sh                   | 15 ++++++---
 t/t7006-pager.sh                          |  6 ++--
 t/t7416-submodule-dash-url.sh             |  3 +-
 t/t7501-commit-basic-functionality.sh     |  6 ++--
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  9 ++---
 t/t8001-annotate.sh                       |  6 ++++
 t/t8002-blame.sh                          |  8 ++++-
 t/t8006-blame-textconv.sh                 |  2 +-
 t/t8011-blame-split-file.sh               |  6 ++--
 t/t8012-blame-colors.sh                   |  6 ++++
 t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib-functions.sh                   | 20 +++--------
 t/test-lib.sh                             | 49 +++++++++++++++++----------
 84 files changed, 471 insertions(+), 373 deletions(-)

Range-diff versus v1:

 1:  83596f2aa05 !  1:  658a45496a3 t: skip chain lint when PERL_PATH is unset
    @@ Metadata
      ## Commit message ##
         t: skip chain lint when PERL_PATH is unset
     
    -    Our chainlint scripts verify that test files have proper '&&' chains.
    -    These scripts are written in Perl and are executed for every test file
    -    before executing the test logic itself.
    +    Our chainlint script verifies that test files have proper '&&' chains.
    +    This script is written in Perl and executed for every test file before
    +    executing the test logic itself.
     
         In subsequent commits we're about to refactor our test suite so that
         Perl becomes an optional dependency, only. And while it is already
 2:  67e9859721d =  2:  12a618f141a t: refactor environment sanitization to not use Perl
 3:  6ebfa6a8581 =  3:  37b5ee501c7 t: adapt character translation helpers to not use Perl
 4:  01e9fce3751 =  4:  df0e1185b3b t: adapt `test_copy_bytes()` to not use Perl
 5:  1f291160713 =  5:  badfad15e0c t: adapt `test_readlink()` to not use Perl
 6:  ab15650ca76 !  6:  ae30c6a1524 t: introduce PERL_TEST_HELPERS prerequisite
    @@ t/t4103-apply-binary.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
      
     +if ! test_have_prereq PERL_TEST_HELPERS
     +then
    -+	skip_all='skipping ignores tests; Perl not available'
    ++	skip_all='skipping apply-binary tests; Perl not available'
     +	test_done
     +fi
     +
 7:  d278b3c6d90 =  7:  8084db771c1 t: adapt existing PERL prerequisites
 8:  bb8b13b2669 =  8:  87b58043c59 meson: stop requiring Perl when tests are enabled
 9:  6b2a77c2dc4 =  9:  b9831e97fca Makefile: stop requiring Perl when running tests
10:  0af780a491b ! 10:  4b3a4f5a1e5 t: refactor tests depending on Perl transliteration operator
    @@ t/t4103-apply-binary.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
      
     -if ! test_have_prereq PERL_TEST_HELPERS
     -then
    --	skip_all='skipping ignores tests; Perl not available'
    +-	skip_all='skipping apply-binary tests; Perl not available'
     -	test_done
     -fi
     -
11:  c57d1a1dc14 ! 11:  20ccdb34dc8 t: refactor tests depending on Perl substitution operator
    @@ t/t0008-ignores.sh: test_stderr () {
      
      broken_c_unquote () {
     -	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
    -+	<"$1" sed -e 's/^"//' -e 's/\\//' -e 's/"$//' | tr '\n' '\0'
    ++	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
      }
      
      broken_c_unquote_verbose () {
     -	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
    -+	<"$1" sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' | tr ':\t\n' '\000'
    ++	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
      }
      
      stderr_contains () {
12:  4cf1615b49a ! 12:  a6c15a4b619 t: refactor tests depending on Perl to print data
    @@ t/t0610-reftable-basics.sh: test_expect_success 'basic: commit and list refs' '
     -		print \"this is a long commit message\" x 50000
     -	" >commit-msg &&
     +
    -+	awk "BEGIN { for (i = 0; i < 50000; i++) print \"this is a long commit message\" }" >commit-msg &&
    ++	awk "BEGIN { for (i = 0; i < 50000; i++) printf \"%s\", \"this is a long commit message\" }" >commit-msg &&
      	git -C repo commit --allow-empty --file=../commit-msg
      '
      
13:  de36109ff9f ! 13:  4e6c4c88d4c t: refactor tests depending on Perl for textconv scripts
    @@ Commit message
         place: we only care that the textconv script does something, and that
         can be verified trivially without having a full-blown invocation of
         hexdump. So at times, the implementation of the textconv scripts is
    -    reduced to their bare minimum.
    +    reduced to their bare minimum and the expectations of those tests are
    +    adapted accordingly.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
14:  ac0537394ab = 14:  28d6a862403 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
15:  96486f46150 ! 15:  17fbc84e23c t/lib-t6000: refactor `name_from_description()` to not depend on Perl
    @@ t/lib-t6000.sh: check_output () {
     +		-e 's/[^A-Za-z0-9.]/-/g' \
     +		-e 's/--*/-/g' \
     +		-e 's/-$//' \
    -+		-e 's/^-//' |
    -+	tr 'A-Z' 'a-z'
    ++		-e 's/^-//' \
    ++		-e 'y/A-Z/a-z/'
      }
      
      
16:  2b418ae8d8f = 16:  de58d23e7ab t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
17:  8eb9b127db6 = 17:  517094e41a6 t0021: refactor `generate_random_characters()` to not depend on Perl
18:  8d0e583f741 = 18:  0eecfc633bd t0210: refactor trace2 scrubbing to not use Perl
19:  7c5dc0d66b1 = 19:  8a2b080c949 t5316: refactor `max_chain()` to not depend on Perl
20:  8a35ab947b5 = 20:  118b00003ea t5703: refactor test to not depend on Perl

---
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
change-id: 20250317-b4-pks-t-perlless-138cf94696b8


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
                     ` (18 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our chainlint script verifies that test files have proper '&&' chains.
This script is written in Perl and executed for every test file before
executing the test logic itself.

In subsequent commits we're about to refactor our test suite so that
Perl becomes an optional dependency, only. And while it is already
possible to disable this linter, developers that don't have Perl
available at all would always have to disable the linter manually, which
is rather cumbersome.

Disable the chain linter automatically in case PERL_PATH isn't set to
make this a bit less annoying. Bail out with an error in case the
developer has asked explicitly for the chain linter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9001ed3a647..1ce3b32fcac 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1523,6 +1523,22 @@ then
 	export LSAN_OPTIONS
 fi
 
+if test -z "$PERL_PATH"
+then
+	case "${GIT_TEST_CHAIN_LINT:-unset}" in
+	unset)
+		GIT_TEST_CHAIN_LINT=0
+		;;
+	0)
+		# The user has explicitly disabled the chain linter, so we
+		# don't have anything to worry about.
+		;;
+	*)
+		BAIL_OUT 'You need Perl for the chain linter'
+		;;
+	esac
+fi
+
 if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
    test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 02/20] t: refactor environment sanitization to not use Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 03/20] t: adapt character translation helpers " Patrick Steinhardt
                     ` (17 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Before executing tests we first sanitize the environment. Part of the
sanitization is to unset a couple of environment variables that we know
will change the behaviour of Git. This is done with a small Perl script,
which has the consequence that having a Perl interpreter available is a
strict requirement for running our unit tests.

The logic itself isn't particularly involved: we simply unset every
environment variable whose key starts with 'GIT_', but then explicitly
allow a subset of these.

Refactor the logic to instead use sed(1) so that it becomes possible to
execute our tests without Perl.

Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1ce3b32fcac..a62699d6c79 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -499,24 +499,20 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
-	my @env = keys %ENV;
-	my $ok = join("|", qw(
-		TRACE
-		DEBUG
-		TEST
-		.*_TEST
-		PROVE
-		VALGRIND
-		UNZIP
-		PERF_
-		CURL_VERBOSE
-		TRACE_CURL
-		BUILD_DIR
-	));
-	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
-	print join("\n", @vars);
-')
+unset VISUAL EMAIL LANGUAGE $(env | sed -n \
+	-e '/^GIT_TRACE/d' \
+	-e '/^GIT_DEBUG/d' \
+	-e '/^GIT_TEST/d' \
+	-e '/^GIT_.*_TEST/d' \
+	-e '/^GIT_PROVE/d' \
+	-e '/^GIT_VALGRIND/d' \
+	-e '/^GIT_UNZIP/d' \
+	-e '/^GIT_PERF_/d' \
+	-e '/^GIT_CURL_VERBOSE/d' \
+	-e '/^GIT_TRACE_CURL/d' \
+	-e '/^GIT_BUILD_DIR/d' \
+	-e 's/^\(GIT_[^=]*\)=.*/\1/p'
+)
 unset XDG_CACHE_HOME
 unset XDG_CONFIG_HOME
 unset GITPERLLIB

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 03/20] t: adapt character translation helpers to not use Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
                     ` (16 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of helper functions that translate characters, e.g.
from LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl
scripts, but they can be trivially adapted to instead use tr(1).

Note that one specialty here is the handling of NUL characters in tr(1),
which historically wasn't implemented correctly on all platforms. But
quoting tr(1p):

    It was considered that automatically stripping NUL characters from
    the input was not correct functionality.  However, the removal of -n
    in a later proposal does not remove the requirement that tr
    correctly process NUL characters in its input stream.

So when tr(1) is implemented following the POSIX standard then it is
expected to handle the transliteration of NUL just fine.

Refactor the helpers accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 79377bc0fc2..377f08a1428 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -88,15 +88,15 @@ test_decode_color () {
 }
 
 lf_to_nul () {
-	perl -pe 'y/\012/\000/'
+	tr '\012' '\000'
 }
 
 nul_to_q () {
-	perl -pe 'y/\000/Q/'
+	tr '\000' 'Q'
 }
 
 q_to_nul () {
-	perl -pe 'y/Q/\000/'
+	tr 'Q' '\000'
 }
 
 q_to_cr () {

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 04/20] t: adapt `test_copy_bytes()` to not use Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 03/20] t: adapt character translation helpers " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
                     ` (15 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_copy_bytes()` helper function copies up to N bytes from stdin
to stdout. This is implemented using Perl, but it can be trivially
adapted to instead use dd(1).

Refactor the helper accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 377f08a1428..c4b4d3a4c7f 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1640,17 +1640,7 @@ test_match_signal () {
 
 # Read up to "$1" bytes (or to EOF) from stdin and write them to stdout.
 test_copy_bytes () {
-	perl -e '
-		my $len = $ARGV[1];
-		while ($len > 0) {
-			my $s;
-			my $nread = sysread(STDIN, $s, $len);
-			die "cannot read: $!" unless defined($nread);
-			last unless $nread;
-			print $s;
-			$len -= $nread;
-		}
-	' - "$1"
+	dd ibs=1 count="$1" 2>/dev/null
 }
 
 # run "$@" inside a non-git directory

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 05/20] t: adapt `test_readlink()` to not use Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (3 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
                     ` (14 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_readlink()` helper function reads a symbolic link and returns
the path it is pointing to. It is thus equivalent to the readlink(1)
utility, which isn't available on all supported platforms. As such, it
is implemented using Perl so that we can use it even on platforms where
the shell utility isn't available.

While using readlink(1) is not an option, what we can do is to implement
the logic ourselves in our test-tool. Do so, which allows a bunch of
tests to pass when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-path-utils.c | 13 +++++++++++++
 t/test-lib-functions.sh    |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 72ac8d1b1b0..54d9ba98c0e 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)
 		return 0;
 	}
 
+	if (argc >= 2 && !strcmp(argv[1], "readlink")) {
+		struct strbuf target = STRBUF_INIT;
+		while (argc > 2) {
+			if (strbuf_readlink(&target, argv[2], 0) < 0)
+				die_errno("cannot read link at '%s'", argv[2]);
+			puts(target.buf);
+			argc--;
+			argv++;
+		}
+		strbuf_release(&target);
+		return 0;
+	}
+
 	if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
 		while (argc > 2) {
 			puts(absolute_path(argv[2]));
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c4b4d3a4c7f..bff8c4d1b41 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1979,7 +1979,7 @@ test_remote_https_urls() {
 # Print the destination of symlink(s) provided as arguments. Basically
 # the same as the readlink command, but it's not available everywhere.
 test_readlink () {
-	perl -le 'print readlink($_) for @ARGV' "$@"
+	test-tool path-utils readlink "$@"
 }
 
 # Set mtime to a fixed "magic" timestamp in mid February 2009, before we

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (4 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
                     ` (13 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

In the early days of Git, Perl was used quite prominently throughout the
project. This has changed significantly as almost all of the executables
we ship nowadays have eventually been rewritten in C. Only a handful of
subsystems remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these subsystems can really be considered to be part of the
"core" of Git, and an installation without them is fully functional.
It is more likely than not that an end user wouldn't even notice that
any features are missing if those tools weren't installed. But while
Perl nowadays very much is an optional dependency of Git, there is a
significant limitation when Perl isn't available: developers cannot run
our test suite.

Preceding commits have started to lift this restriction by removing the
strict dependency on Perl in many central parts of the test library. But
there are still many tests that rely on small Perl helpers to do various
different things.

Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
that require Perl. This prerequisite is explicitly different than the
preexisting PERL prerequisite:

  - PERL records whether or not features depending on the Perl
    interpreter are built.

  - PERL_TEST_HELPERS records whether or not a Perl interpreter is
    available for our tests.

By having these two separate prerequisites we can thus distinguish
between tests that inherently depend on Perl because the underlying
feature does, and those tests that depend on Perl because the test
itself is using Perl.

Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        |  6 ++++++
 t/t0021-conversion.sh                     |  4 ++--
 t/t0210-trace2-normal.sh                  |  6 ++++++
 t/t0211-trace2-perf.sh                    |  6 ++++++
 t/t0610-reftable-basics.sh                |  2 +-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       |  2 +-
 t/t1007-hash-object.sh                    |  6 +++---
 t/t1010-mktree.sh                         |  4 ++--
 t/t1450-fsck.sh                           |  6 +++---
 t/t3300-funny-names.sh                    |  6 +++---
 t/t4013-diff-various.sh                   |  6 ++++++
 t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------
 t/t4020-diff-external.sh                  |  4 ++--
 t/t4029-diff-trailing-space.sh            |  2 +-
 t/t4030-diff-textconv.sh                  |  6 ++++++
 t/t4031-diff-rewrite-binary.sh            |  2 +-
 t/t4058-diff-duplicates.sh                |  6 ++++++
 t/t4103-apply-binary.sh                   |  6 ++++++
 t/t4116-apply-reverse.sh                  |  6 ++++++
 t/t4150-am.sh                             |  2 +-
 t/t4200-rerere.sh                         |  6 ++++++
 t/t4205-log-pretty-formats.sh             |  6 +++---
 t/t4216-log-bloom.sh                      |  8 ++++----
 t/t5004-archive-corner-cases.sh           |  6 ++++++
 t/t5300-pack-object.sh                    |  6 ++++++
 t/t5303-pack-corruption-resilience.sh     |  4 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               |  8 ++++----
 t/t5318-commit-graph.sh                   | 12 ++++++------
 t/t5319-multi-pack-index.sh               | 16 ++++++++--------
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  2 +-
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  4 ++--
 t/t5503-tagfollow.sh                      |  6 ++++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++++
 t/t5532-fetch-proxy.sh                    |  6 ++++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  |  2 +-
 t/t5551-http-fetch-smart.sh               |  7 +++++++
 t/t5562-http-backend-content-length.sh    |  6 ++++++
 t/t5601-clone.sh                          |  4 ++--
 t/t5616-partial-clone.sh                  |  6 +++---
 t/t5701-git-serve.sh                      |  2 +-
 t/t5702-protocol-v2.sh                    |  6 +++---
 t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++
 t/t5710-promisor-remote-capability.sh     |  6 ++++++
 t/t6002-rev-list-bisect.sh                |  6 ++++++
 t/t6003-rev-list-topo-order.sh            |  6 ++++++
 t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++
 t/t6013-rev-list-reverse-parents.sh       |  4 ++--
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++
 t/t6115-rev-list-du.sh                    |  6 ++++++
 t/t6300-for-each-ref.sh                   |  6 ++++++
 t/t7006-pager.sh                          |  2 +-
 t/t7416-submodule-dash-url.sh             |  6 ++++++
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  6 ++++++
 t/t8001-annotate.sh                       |  6 ++++++
 t/t8002-blame.sh                          |  6 ++++++
 t/t8006-blame-textconv.sh                 |  6 ++++++
 t/t8011-blame-split-file.sh               |  6 +++---
 t/t8012-blame-colors.sh                   |  6 ++++++
 t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib.sh                             |  1 +
 71 files changed, 281 insertions(+), 93 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index c9376dffb58..1aaa6bf5ae8 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,6 +5,12 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping ignores tests; Perl not available'
+	test_done
+fi
+
 init_vars () {
 	global_excludes="global-excludes"
 }
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 3f6433d3045..9c3738ebb3f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success 'required process filter should process multiple packets' '
+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '
 	)
 '
 
-test_expect_success 'required process filter with clean error should fail' '
+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index 4287ed3fbb3..ba4c0442b85 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index bac90465406..760cf69087f 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_PERF_BRIEF
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 4618ffc108e..5e0a1fa176d 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success 'basic: can write large commit message' '
+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	perl -e "
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index e2708e11d5b..fa1e2f9eef8 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success 'small block size fails with large reflog message' '
+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 398865d6ebe..a574da3df53 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1270,7 +1270,7 @@ extract_batch_output () {
     ' "$@"
 }
 
-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '
 	git cat-file --batch-all-objects --batch >actual.raw &&
 	extract_batch_output $orig <actual.raw >actual &&
 	{
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index a0481139de5..b3cf53ff8c9 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '
 	grep "too-short tree object" err
 '
 
-test_expect_success 'malformed mode in tree' '
+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "9100644 \0$bin_oid" >tree-with-malformed-mode &&
@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '
 	grep "malformed mode in tree entry" err
 '
 
-test_expect_success 'empty filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "100644 \0$bin_oid" >tree-with-empty-filename &&
@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '
 	grep "empty filename in tree entry" err
 '
 
-test_expect_success 'duplicate filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	{
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index c291a2b33d7..4977998e205 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
 	perl -e "print reverse <>" <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
 	perl -e "print reverse <>" <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1142d..01050453762 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '
 	test_grep ! "fatal: empty filename in tree entry" out
 '
 
-test_expect_success 'tree entry with type mismatch' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	test_when_finished "remove_object \$commit" &&
@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '
 	test_grep ! "dangling blob" out
 '
 
-test_expect_success 'tree entry with bogus mode' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	blob=$(echo blob | git hash-object -w --stdin) &&
@@ -984,7 +984,7 @@ corrupt_index_checksum () {
 
 # Corrupt the checksum on the index and then
 # verify that only fsck notices.
-test_expect_success 'detect corrupt index file in fsck' '
+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '
 	cp .git/index .git/index.backup &&
 	test_when_finished "mv .git/index.backup .git/index" &&
 	corrupt_index_checksum &&
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index f5bf16abcd8..502b1572059 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'ls-files -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-index -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-tree -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68dbc0..782d97fb7df 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff various tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83fb8a4..2782b1fc183 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF
 ---
 EOF
 
-test_expect_success 'no threading' '
+test_expect_success PERL_TEST_HELPERS 'no threading' '
 	git checkout side &&
 	check_threading expect.no-threading main
 '
@@ -466,11 +466,11 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread' '
+test_expect_success PERL_TEST_HELPERS 'thread' '
 	check_threading expect.thread --thread main
 '
 
-test_expect_success '--thread overrides format.thread=deep' '
+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
@@ -490,7 +490,7 @@ In-Reply-To: <1>
 References: <1>
 EOF
 
-test_expect_success 'thread in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '
 	check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 		--thread main
 '
@@ -512,7 +512,7 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '
 	check_threading expect.cover-letter --cover-letter --thread main
 '
 
@@ -538,12 +538,12 @@ References: <1>
 	<0>
 EOF
 
-test_expect_success 'thread cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread main
 '
 
-test_expect_success 'thread explicit shallow' '
+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=shallow main
 '
@@ -562,7 +562,7 @@ References: <0>
 	<1>
 EOF
 
-test_expect_success 'thread deep' '
+test_expect_success PERL_TEST_HELPERS 'thread deep' '
 	check_threading expect.deep --thread=deep main
 '
 
@@ -584,7 +584,7 @@ References: <1>
 	<2>
 EOF
 
-test_expect_success 'thread deep in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '
 	check_threading expect.deep-irt  --thread=deep \
 		--in-reply-to="<test.message>" main
 '
@@ -609,7 +609,7 @@ References: <0>
 	<2>
 EOF
 
-test_expect_success 'thread deep cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '
 	check_threading expect.deep-cl --cover-letter --thread=deep main
 '
 
@@ -638,27 +638,27 @@ References: <1>
 	<3>
 EOF
 
-test_expect_success 'thread deep cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '
 	check_threading expect.deep-cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=deep main
 '
 
-test_expect_success 'thread via config' '
+test_expect_success PERL_TEST_HELPERS 'thread via config' '
 	test_config format.thread true &&
 	check_threading expect.thread main
 '
 
-test_expect_success 'thread deep via config' '
+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '
 	test_config format.thread deep &&
 	check_threading expect.deep main
 '
 
-test_expect_success 'thread config + override' '
+test_expect_success PERL_TEST_HELPERS 'thread config + override' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
 
-test_expect_success 'thread config + --no-thread' '
+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '
 	test_config format.thread deep &&
 	check_threading expect.no-threading --no-thread main
 '
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index f1efe482a59..189294de7ef 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet
 
 echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
 
-test_expect_success 'force diff with "diff"' '
+test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success 'diff --cached' '
+test_expect_success PERL_TEST_HELPERS 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index 32b6e9a4e76..a92a42990b1 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success "$test_description" '
+test_expect_success PERL_TEST_HELPERS "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index daebf9796f5..c7d8eb12453 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff textconv tests; Perl not available'
+	test_done
+fi
+
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index c4394a27b56..cbe50b15772 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success 'rewrite diff respects textconv' '
+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
 	git diff -B >diff &&
 	grep "dissimilarity index" diff &&
 	grep "^-61" diff &&
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2fce4a98977..16266dff2af 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff duplicates tests; Perl not available'
+	test_done
+fi
+
 # make_tree_entry <mode> <mode> <sha1>
 #
 # We have to rely on perl here because not all printfs understand
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index d370ecfe0d9..59d38793ae6 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply-binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 0784ba033a4..6f414ad27f5 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,6 +10,12 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply reverse tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c80eae..4794510d70d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success 'am works with multi-line in-body headers' '
+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b0a3e849841..50fe8b0fd05 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rerere tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f81e42a84d5..8f2ba98963f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trail
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:unfold) unfolds trailers' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '
 	git log --no-walk --pretty="%(trailers:unfold)" >actual &&
 	{
 		unfold <trailers &&
@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '
 	test_cmp expect actual
 '
 
-test_expect_success ':only and :unfold work together' '
+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '
 	git log --no-walk --pretty="%(trailers:only,unfold)" >actual &&
 	git log --no-walk --pretty="%(trailers:unfold,only)" >reverse &&
 	test_cmp actual reverse &&
@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '
 	git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual &&
 	unfold <trailers | grep Signed-off-by >expect &&
 	test_cmp expect actual
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 3f163dc3969..8910d53cac1 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -738,20 +738,20 @@ check_corrupt_graph () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'Bloom reader notices too-small data chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
 	check_corrupt_graph BDAT clear 00000000 &&
 	echo "warning: ignoring too-small changed-path chunk" \
 		"(4 < 12) in commit-graph file" >expect.err &&
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
 	check_corrupt_graph BIDX 12 FFFFFFFF &&
 	# use grep to avoid depending on exact chunk size
 	grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
 '
 
-test_expect_success 'Bloom reader notices too-small index chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
 	# replace the index with a single entry, making most
 	# lookups out-of-bounds
 	check_corrupt_graph BIDX clear 00000000 &&
@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-order index offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
 	# we do not know any real offsets, but we can pick
 	# something plausible; we should not get to the point of
 	# actually reading from the bogus offsets anyway.
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 50344e17ca1..51749951916 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping archive corner cases tests; Perl not available'
+	test_done
+fi
+
 # the 10knuls.tar file is used to test for an empty git generated tar
 # without having to invoke tar because an otherwise valid empty GNU tar
 # will be considered broken by {Open,Net}BSD tar
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 5ac8d39094b..143856c29f1 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,6 +7,12 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pack-object tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	rm -f .git/index* &&
 	perl -e "print \"a\" x 4096;" >a &&
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index de58ca654a1..ac5e370e1e4 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first object' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
@@ -156,7 +156,7 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first delta' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 621bbbdd26e..81987296235 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 32cf4227451..cd947b5a5ef 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -87,7 +87,7 @@ max_chain() {
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success 'packing produces a long delta' '
+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success '--depth limits depth' '
+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success '--depth=0 disables deltas' '
+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success 'negative depth disables deltas' '
+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index f68f64cd85e..0b3404f58fe 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -837,7 +837,7 @@ check_corrupt_chunk () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	# make it big enough that the graph file is plausible,
 	# otherwise we hit an earlier check
 	check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices fanout/lookup table mismatch' '
+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '
 	check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph OID lookup chunk is the wrong size
@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# Rather than try to corrupt a specific hash, we will just
 	# wreck them all. But we cannot just set them all to 0xFFFFFFFF or
 	# similar, as they are used for hi/lo starts in a binary search (so if
@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small commit data chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '
 	check_corrupt_chunk CDAT clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph commit data chunk is wrong size
@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds extra edge' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '
 	check_corrupt_chunk EDGE clear &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph extra-edges pointer out of bounds
@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small generations chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '
 	check_corrupt_chunk GDA2 clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph generations chunk is wrong size
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 0f215ad2e88..bd75dea9501 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1120,7 +1120,7 @@ corrupt_chunk () {
 	corrupt_chunk_file $midx "$@"
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	corrupt_chunk OIDF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small oid lookup chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '
 	corrupt_chunk OIDL clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small pack names chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '
 	# There is no NUL to terminate the name here, so the
 	# chunk is too short.
 	corrupt_chunk PNAM clear 70656666 &&
@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader handles unaligned chunks' '
+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '
 	# A 9-byte PNAM means all of the subsequent chunks
 	# will no longer be 4-byte aligned, but it is still
 	# a valid one-pack chunk on its own (it is "foo.pack\0").
@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small object offset chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '
 	corrupt_chunk OOFF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader bounds-checks large offset table' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '
 	# re-use the objects64 dir here to cheaply get access to a midx
 	# with large offsets.
 	git init repo &&
@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '
 	)
 '
 
-test_expect_success 'reader notices too-small revindex chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '
 	# We only get a revindex with bitmaps (and likewise only
 	# load it when they are asked for).
 	test_config repack.writeBitmaps true &&
@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# This is similar to the out-of-bounds fanout test in t5318. The values
 	# in adjacent entries should be large but not identical (they
 	# are used as hi/lo starts for a binary search, which would then abort
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index a32be3867df..49a057cc2eb 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '
 	)
 '
 
-test_expect_success 'reader bounds-checks base-graph chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '
 	git clone --no-hardlinks . corrupt-base-chunk &&
 	(
 		cd corrupt-base-chunk &&
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index d27557b9b04..627f8b4efdc 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index a766a3e3f84..d8891e6a922 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
 	git -C repo-uint32-max commit-graph verify
 '
 
-test_expect_success 'reader notices out-of-bounds generation overflow' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '
 	graph=.git/objects/info/commit-graph &&
 	test_when_finished "rm -rf $graph" &&
 	git commit-graph write --reachable &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 3905cb6e4f1..1059ff45fe4 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
+	test_done
+fi
+
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16e133..571e8f1bc59 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -268,7 +268,7 @@ extract_ref_advertisement () {
 	'
 }
 
-test_expect_success 'receive-pack de-dupes .have lines' '
+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '
 	git init shared &&
 	git -C shared commit --allow-empty -m both &&
 	git clone -s shared fork &&
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 0b28e4e452f..6a009fdcd71 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -20,7 +20,7 @@ extract_haves () {
 	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
 }
 
-test_expect_success 'with core.alternateRefsCommand' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success 'with core.alternateRefsPrefixes' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 845ca43ea0a..febe4410417 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping tagfollow tests; Perl not available'
+	test_done
+fi
+
 # End state of the repository:
 #
 #         T - tag1          S - tag2
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 58074506c59..438250c75ed 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -359,7 +359,7 @@ test_expect_success \
 	grep "Cannot demote unterminatedheader" act
 '
 
-test_expect_success 'badFilemode is not a strict error' '
+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '
 	git init --bare badmode.git &&
 	tree=$(
 		cd badmode.git &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 5f350facf5e..432a2264e6f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -8,6 +8,12 @@ test_description='Per branch config variables affects "git fetch".
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch tests; Perl not available'
+	test_done
+fi
+
 D=$(pwd)
 
 test_expect_success setup '
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
index 37558226290..95d0f33b295 100755
--- a/t/t5532-fetch-proxy.sh
+++ b/t/t5532-fetch-proxy.sh
@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch proxy tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup remote repo' '
 	git init remote &&
 	(cd remote &&
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index c91a62b77af..342d0423c92 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 37f7547a4ca..77d20d19110 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 761fdfcfe6c..b0d4ea78015 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
+
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http fetch smart tests; Perl not available'
+	test_done
+fi
+
 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
 start_httpd
 
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index f3b158274c4..b6ee06f5c8f 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http backend content tests; Perl not available'
+	test_done
+fi
+
 test_lazy_prereq GZIP 'gzip --version'
 
 verify_http_result() {
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d0c18660e33..d743d986c40 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
 	git -C replay.git index-pack -v --stdin <tmp.pack
 '
 
-test_expect_success 'clone on case-insensitive fs' '
+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '
 	git init icasefs &&
 	(
 		cd icasefs &&
@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '
 	)
 '
 
-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '
 	grep X icasefs/warning &&
 	grep x icasefs/warning &&
 	test_grep "the following paths have collided" icasefs/warning
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 46504519643..bc7e0fec8dc 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -751,7 +751,7 @@ replace_packfile () {
 	}' >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
-test_expect_success 'upon cloning, check that all refs point to objects' '
+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 678a346ed06..200bf06ecb3 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success 'ignore very large set of prefixes' '
+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index d3df81e7852..ad5e772cd72 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success 'when server sends "ready", expect DELIM' '
+test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends "ready", expect DELIM' '
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success 'when server does not send "ready", expect FLUSH' '
+test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
 	URI="$HTTPD_URL/one_time_perl/server" &&
 
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 191097171bc..f59d47aa6c6 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
+	test_done
+fi
+
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index d2cc69a17e4..9a420cf5605 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping promisor remote capabilities tests; Perl not available'
+	test_done
+fi
+
 GIT_TEST_MULTI_PACK_INDEX=0
 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index daa009c9a1b..5e1482aff78 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list bisect tests; Perl not available'
+	test_done
+fi
+
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 0d7055d46d4..02dd4127aff 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list topo-order tests; Perl not available'
+	test_done
+fi
+
 list_duplicates()
 {
     "$@" | sort | uniq -d
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index bad02cf5b83..6131c361094 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list with bad commit tests; Perl not available'
+	test_done
+fi
+
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 39793cbbd66..8074185742c 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success '--reverse --parents --full-history combines correctly' '
+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
 	git rev-list --parents --full-history main -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '
 	test_cmp expected actual
 	'
 
-test_expect_success '--boundary does too' '
+test_expect_success PERL_TEST_HELPERS '--boundary does too' '
 	git rev-list --boundary --parents --full-history main ^root -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --boundary --reverse --parents --full-history \
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 22dfd6d978e..eb98b3919c8 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list unexpected objects tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup well-formed objects' '
 	blob="$(printf "foo" | git hash-object -w --stdin)" &&
 	tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 3385fe9f130..6a74be576a2 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list disk usage tests; Perl not available'
+	test_done
+fi
+
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a5c77943854..732a4d3171e 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping for-each-ref tests; Perl not available'
+	test_done
+fi
+
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 932c26cb45b..49aae183829 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success 'setup large log output' '
+test_expect_success PERL_TEST_HELPERS 'setup large log output' '
 	perl -e "
 		print \"this is a long commit message\" x 50000
 	" >commit-msg &&
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 0c605fd271a..14069600a2f 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping submodule dash URL tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index b2070d4e39f..14c41b2cb7c 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success 'status -z implies porcelain' '
+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
 	git status --porcelain |
 	perl -pe "s/\012/\000/g" >expect &&
 	git status -z >output &&
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index 90ebb64f46e..b2730d200c8 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,6 +4,12 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping grep binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index d7167f55397..609845aeb1e 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping annotate tests; Perl not available'
+	test_done
+fi
+
 PROG='git annotate'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index e98993276a6..b40199df231 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 07a287ffd3e..5cb16872081 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,6 +4,12 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame textconv tests; Perl not available'
+	test_done
+fi
+
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh
index c66494f5ba7..388057245c8 100755
--- a/t/t8011-blame-split-file.sh
+++ b/t/t8011-blame-split-file.sh
@@ -81,7 +81,7 @@ do
 		git blame --root -C --$output combined >output
 	'
 
-	test_expect_success "$output output finds correct commits" '
+	test_expect_success PERL_TEST_HELPERS "$output output finds correct commits" '
 		generate_expect >expect <<-\EOF &&
 		5 base
 		1 modified
@@ -93,7 +93,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct filenames" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct filenames" '
 		generate_expect >expect <<-\EOF &&
 		11 one
 		11 two
@@ -102,7 +102,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct previous pointer" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct previous pointer" '
 		generate_expect >expect <<-EOF &&
 		5 NONE
 		1 $(git rev-parse modified^) one
diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh
index c3a5f6d01ff..3d77352650f 100755
--- a/t/t8012-blame-colors.sh
+++ b/t/t8012-blame-colors.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index 067b15bad25..a9d38be997c 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' '
+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success 'change file but in unrelated area' "
+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
 	perl -i.bak -p -e 's/^4\$/4444/' file &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 40427883ec6..0781a8d6ace 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '
 	(cd result && git show main:foo)
 '
 
-test_expect_success 'fast-export quotes pathnames' '
+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '
 	git init crazy-paths &&
 	test_config -C crazy-paths core.protectNTFS false &&
 	(cd crazy-paths &&
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index 36566ace21b..f619b60f226 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success 'shell complains of overlong commands' '
+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
 	perl -e "print \"a\" x 2**12 for (0..2**19)" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a62699d6c79..59162a3c834 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1706,6 +1706,7 @@ test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
 test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
 test -n "$GIT_VALGRIND_ENABLED" && test_set_prereq VALGRIND
+test -n "$PERL_PATH" && test_set_prereq PERL_TEST_HELPERS
 
 if test -z "$GIT_TEST_CHECK_CACHE_TREE"
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 07/20] t: adapt existing PERL prerequisites
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (5 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
                     ` (12 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A couple of our tests depend on the PERL prerequisite even though it
isn't needed. These tests fall into one of the following classes:

  - The underlying logic used to be implemented in Perl but isn't
    anymore. Here we can simply drop the dependency altogether.

  - The test logic used to depend on Perl but doesn't anymore. Again, we
    can simply drop the dependency.

  - The test logic still relies on a Perl interpreter. These tests
    should use the newly introduced PERL_TEST_HELPERS prerequisite.

Adapt test cases accordingly.

Note that in t1006 we have to introduce another new prerequisite
depending on whether or not the IPC::Open2 module is available. Funny
enough, when starting to use `test_lazy_prereq` to do so we also get a
conflict of variables with the "script" variable that contains the Perl
logic because `test_run_lazy_prereq_` also sets that variable. We thus
rename the variable in t1006 to "perl_script".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh                 | 10 +++++-----
 t/t0090-cache-tree.sh                 |  4 ++--
 t/t1006-cat-file.sh                   | 14 +++++++++-----
 t/t7501-commit-basic-functionality.sh |  6 +++---
 4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9c3738ebb3f..4a892a91780 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'
 	)
 '
 
-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
+test_expect_success 'invalid process filter must fail (and not hang!)' '
 	test_config_global filter.protocol.process cat &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
@@ -1111,19 +1111,19 @@ do
 	branch) opt='-f HEAD' ;;
 	esac
 
-	test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
+	test_expect_success TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
 		test_delayed_checkout_progress test_terminal git checkout $opt
 	'
 
-	test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" '
+	test_expect_success "delayed checkout omits progress on non-tty ($mode checkout)" '
 		test_delayed_checkout_progress ! git checkout $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
+	test_expect_success TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
+	test_expect_success TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&
 		test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt
 	'
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index ab80c9ef135..d9015882946 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '
 	test_cache_tree
 '
 
-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
 	test_when_finished "git reset --hard" &&
 	cat <<-\EOT >foo.c &&
 	int foo()
@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
 	test_cache_tree expected.status
 '
 
-test_expect_success PERL 'commit -p with shrinking cache-tree' '
+test_expect_success 'commit -p with shrinking cache-tree' '
 	mkdir -p deep/very-long-subdir &&
 	echo content >deep/very-long-subdir/file &&
 	git add deep &&
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index a574da3df53..0a22b0a7b8e 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '
 	grep "^fatal:.*flush is only for --buffer mode.*" err
 '
 
-script='
+perl_script='
 use warnings;
 use strict;
 use IPC::Open2;
@@ -1345,12 +1345,16 @@ $? == 0 or die "\$?=$?";
 
 expect="$hello_oid blob $hello_size"
 
-test_expect_success PERL '--batch-check is unbuffered by default' '
-	perl -e "$script" -- --batch-check $hello_oid "$expect"
+test_lazy_prereq PERL_IPC_OPEN2 '
+	perl -MIPC::Open2 -e "exit 0"
 '
 
-test_expect_success PERL '--batch-command info is unbuffered by default' '
-	perl -e "$script" -- --batch-command $hello_oid "$expect" "info "
+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-check $hello_oid "$expect"
+'
+
+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-command $hello_oid "$expect" "info "
 '
 
 test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index cc12f99f115..a37509f0043 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '
 	test_must_fail git commit -m foo -a file
 '
 
-test_expect_success PERL 'can use paths with --interactive' '
+test_expect_success 'can use paths with --interactive' '
 	echo bong-o-bong >file &&
 	# 2: update, 1:st path, that is all, 7: quit
 	test_write_lines 2 1 "" 7 |
@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '
 	grep Rubber.Duck output
 '
 
-test_expect_success PERL 'interactive add' '
+test_expect_success 'interactive add' '
 	echo 7 | test_must_fail git commit --interactive >out &&
 	grep "What now" out
 '
 
-test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
+test_expect_success "commit --interactive doesn't change index if editor aborts" '
 	echo zoo >file &&
 	test_must_fail git diff --exit-code >diff1 &&
 	test_write_lines u "*" q |

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 08/20] meson: stop requiring Perl when tests are enabled
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (6 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
                     ` (11 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Perl interpreter used to be a strict dependency for running our test
suite. This requirement is explicit in the Meson build system, where we
require Perl to be present unless tests have been disabled.

With the preceding commits we have loosened this restriction so that it
is now possible to run tests when Perl is unavailable. Loosen the above
requirement accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index efe2871c9db..d6e27b236fa 100644
--- a/meson.build
+++ b/meson.build
@@ -772,7 +772,7 @@ endif
 # features. It is optional if you want to neither execute tests nor use any of
 # these optional features.
 perl_required = get_option('perl')
-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
   perl_required = true
 endif
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 09/20] Makefile: stop requiring Perl when running tests
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (7 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
                     ` (10 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Makefile for our tests has a couple of targets that depend on Perl.
Adapt those targets to only run conditionally in case Perl is available
on the system so that it becomes possible to run the test suite without
Perl.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/Makefile | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/t/Makefile b/t/Makefile
index 2994eb5fa9a..791e0a09789 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT
 
 all:: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean check-chainlint check-meson $(TEST_LINT)
+test: pre-clean check-meson $(TEST_LINT)
 	$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
 
+ifneq ($(PERL_PATH),)
+test: check-chainlint
+prove: check-chainlint
+endif
+
 failed:
 	@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \
 		grep -l '^failed [1-9]' *.counts | \
 		sed -n 's/\.counts$$/.sh/p') && \
 	test -z "$$failed" || $(MAKE) $$failed
 
-prove: pre-clean check-chainlint $(TEST_LINT)
+prove: pre-clean $(TEST_LINT)
 	@echo "*** prove (shell & unit tests) ***"
 	@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
 	$(MAKE) clean-except-prove-cache
@@ -132,8 +137,13 @@ check-meson:
 		fi; \
 	done
 
-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
+test-lint: test-lint-duplicates test-lint-executable \
 	test-lint-filenames
+ifneq ($(PERL_PATH),)
+test-lint: test-lint-shell-syntax
+else
+GIT_TEST_CHAIN_LINT = 0
+endif
 ifneq ($(GIT_TEST_CHAIN_LINT),0)
 test-lint: test-chainlint
 endif

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 10/20] t: refactor tests depending on Perl transliteration operator
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (8 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
                     ` (9 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform character
transliteration via the "y/" or "tr/" operator. These usecases can be
trivially replaced with tr(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-sha1.sh    |  4 ++--
 t/lib-diff.sh            |  4 ++--
 t/t3300-funny-names.sh   | 12 ++++++------
 t/t4020-diff-external.sh |  6 +++---
 t/t4103-apply-binary.sh  | 12 +++---------
 t/t4116-apply-reverse.sh | 10 ++--------
 t/t4200-rerere.sh        |  2 +-
 7 files changed, 19 insertions(+), 31 deletions(-)

diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index bf387d3db14..f03b784ddc2 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -15,7 +15,7 @@ do
 			{
 				test -z "$pfx" || echo "$pfx"
 				dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-				perl -pe 'y/\000/g/'
+				tr "\000" "g"
 			} | ./t/helper/test-tool $sha1 $cnt
 		)
 		if test "$expect" = "$actual"
@@ -61,7 +61,7 @@ do
 		{
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-			perl -pe 'y/\000/g/'
+			tr "\000" "g"
 		} | sha1sum |
 		sed -e 's/ .*//'
 	)
diff --git a/t/lib-diff.sh b/t/lib-diff.sh
index c4606bd4b7f..12b3c8fcc6a 100644
--- a/t/lib-diff.sh
+++ b/t/lib-diff.sh
@@ -21,8 +21,8 @@ compare_diff_raw_z () {
     # Also we do not check SHA1 hash generation in this test, which
     # is a job for t0000-basic.sh
 
-    perl -pe 'y/\000/\012/' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
-    perl -pe 'y/\000/\012/' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
+    tr "\000" "\012" <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
+    tr "\000" "\012" <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 502b1572059..dd0586b0073 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
+test_expect_success 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
 	tabs	," (dq) and spaces
 	EOF
 	git ls-files -z >ls-files.z &&
-	perl -pe "y/\000/\012/" <ls-files.z >current &&
+	tr "\000" "\012" <ls-files.z >current &&
 	test_cmp expected current
 '
 
@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
+test_expect_success 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-index -z --name-status $t0 >diff-index.z &&
-	perl -pe "y/\000/\012/" <diff-index.z >current &&
+	tr "\000" "\012" <diff-index.z >current &&
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
+test_expect_success 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-tree -z --name-status $t0 $t1 >diff-tree.z &&
-	perl -pe y/\\000/\\012/ <diff-tree.z >current &&
+	tr "\000" "\012" <diff-tree.z >current &&
 	test_cmp expected current
 '
 
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 189294de7ef..c8a23d51483 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet
 check_external_diff   1 empty  empty 1 on  --quiet
 check_external_diff 128 empty  error 2 on  --quiet
 
-echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
+echo NULZbetweenZwords | tr "Z" "\000" > file
 
-test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
+test_expect_success 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff --cached' '
+test_expect_success 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index 59d38793ae6..8e302a5a57e 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply-binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
@@ -32,10 +26,10 @@ test_expect_success 'setup' '
 	git commit -m "Initial Version" 2>/dev/null &&
 
 	git checkout -b binary &&
-	perl -pe "y/x/\000/" <file1 >file3 &&
+	tr "x" "\000" <file1 >file3 &&
 	cat file3 >file4 &&
 	git add file2 &&
-	perl -pe "y/\000/v/" <file3 >file1 &&
+	tr "y" "\000" <file3 >file1 &&
 	rm -f file2 &&
 	git update-index --add --remove file1 file2 file3 file4 &&
 	git commit -m "Second Version" &&
@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '
 	test -z "$(git diff --name-status binary -- file3)"
 '
 
-test_expect_success 'reject truncated binary diff' '
+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '
 	do_reset &&
 
 	# this length is calculated to get us very close to
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 6f414ad27f5..1e7beab0016 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,23 +10,17 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply reverse tests; Perl not available'
-	test_done
-fi
-
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
-	perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 &&
+	tr "ijk" "\000\001\002" <file1 >file2 &&
 
 	git add file1 file2 &&
 	git commit -m initial &&
 	git tag initial &&
 
 	test_write_lines a b c g h i J K L m o n p q >file1 &&
-	perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 &&
+	tr "mon" "\000\001\002" <file1 >file2 &&
 
 	git commit -a -m second &&
 	git tag second &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 50fe8b0fd05..7fcca9ddad5 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '
 
 test_expect_success 'rerere clear' '
 	mv $rr/postimage .git/post-saved &&
-	echo "$sha1	a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
+	echo "$sha1	a1" | tr "\012" "\000" >.git/MERGE_RR &&
 	git rerere clear &&
 	! test -d $rr
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (9 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 14:35     ` Phillip Wood
  2025-03-25 13:14   ` [PATCH v2 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
                     ` (8 subsequent siblings)
  19 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform substitution via the
"s/" operator. These usecases can be trivially replaced with sed(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        | 10 ++--------
 t/t4029-diff-trailing-space.sh            |  5 +++--
 t/t4200-rerere.sh                         | 12 +++---------
 t/t5303-pack-corruption-resilience.sh     | 10 ++++++----
 t/t5310-pack-bitmaps.sh                   |  4 ++--
 t/t5534-push-signed.sh                    |  4 ++--
 t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------
 t/t7416-submodule-dash-url.sh             |  9 ++-------
 t/t7508-status.sh                         |  4 ++--
 t/t8006-blame-textconv.sh                 |  8 +-------
 t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------
 11 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 1aaa6bf5ae8..273d71411fe 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,12 +5,6 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping ignores tests; Perl not available'
-	test_done
-fi
-
 init_vars () {
 	global_excludes="global-excludes"
 }
@@ -45,11 +39,11 @@ test_stderr () {
 }
 
 broken_c_unquote () {
-	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
+	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
 }
 
 broken_c_unquote_verbose () {
-	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
+	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
 }
 
 stderr_contains () {
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index a92a42990b1..db75998e35f 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success PERL_TEST_HELPERS "$test_description" '
+test_expect_success "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
 	git config --bool diff.suppressBlankEmpty true &&
 	git diff f > actual &&
 	test_cmp exp actual &&
-	perl -i.bak -p -e "s/^\$/ /" exp &&
+	sed "s/^\$/ /" <exp >exp.munged &&
+	mv exp.munged exp &&
 	git config --bool diff.suppressBlankEmpty false &&
 	git diff f > actual &&
 	test_cmp exp actual &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 7fcca9ddad5..bacb93d014f 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rerere tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
 	test_might_fail git config --unset rerere.enabled &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep "^=======\$" $rr/preimage &&
 	! test -f $rr/postimage &&
@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
 	git reset --hard &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep ^=======$ $rr/preimage
 '
@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
 	git config rerere.enabled true &&
 	git reset --hard &&
 	test_must_fail git merge first &&
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1
 '
 
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index ac5e370e1e4..07382797bbb 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
+test_expect_success 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
+	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	test_must_fail git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
@@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
+test_expect_success 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
+	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 81987296235..9033d72b8c7 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -421,7 +421,7 @@ test_bitmap_cases () {
 
 			# mark the commits which did not receive bitmaps as preferred,
 			# and generate the bitmap again
-			perl -pe "s{^}{create refs/tags/include/$. }" <before |
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
 				git update-ref --stdin &&
 			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
 
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 342d0423c92..d5c0d00114e 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
 	# Tweak the push output to make the push option outside the cert
 	# different, then replay it on a fresh dst, checking that ff is not
 	# deleted.
-	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
+	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
 	git -C dst config receive.advertisepushoptions 1 &&
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index 6131c361094..12329aab388 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list with bad commit tests; Perl not available'
-	test_done
-fi
-
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
    first_commit=$(git rev-parse HEAD~3)
    '
 
-test_expect_success 'corrupt second commit object' \
-   '
-   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
-   test_must_fail git fsck --full
-   '
+test_expect_success 'corrupt second commit object' '
+	for p in .git/objects/pack/*.pack
+	do
+		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
+		mv "$p.munged" "$p" ||
+		return 1
+	done &&
+	test_must_fail git fsck --full
+'
 
 test_expect_success 'rev-list should fail' '
 	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 14069600a2f..00b81d349b9 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping submodule dash URL tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
 '
 
 test_expect_success 'remove ./ protection from .gitmodules url' '
-	perl -i -pe "s{\./}{}" .gitmodules &&
+	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
+	mv .gitmodules.munged .gitmodules &&
 	git commit -am "drop protection"
 '
 
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 14c41b2cb7c..cdc1d6fcc78 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
+test_expect_success 'status -z implies porcelain' '
 	git status --porcelain |
-	perl -pe "s/\012/\000/g" >expect &&
+	tr "\012" "\000" >expect &&
 	git status -z >output &&
 	test_cmp expect output
 '
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 5cb16872081..810dac18f56 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,12 +4,6 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping blame textconv tests; Perl not available'
-	test_done
-fi
-
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
@@ -17,7 +11,7 @@ find_blame() {
 cat >helper <<'EOF'
 #!/bin/sh
 grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
-"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
+sed 's/^bin: /converted: /' <"$1"
 EOF
 chmod +x helper
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index a9d38be997c..9afdb45b1cc 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
+test_expect_success '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
 	(cd tmp &&
-		perl -i.bak -p -e "s/^58$/5588/" file &&
-		perl -i.bak -p -e "s/^61$/6611/" file &&
+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
+		mv file.munged file &&
 		poke file &&
 		test x"$(sed -n -e 58p < file)" = x5588 &&
 		test x"$(sed -n -e 61p < file)" = x6611 &&
@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
+test_expect_success 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
-	perl -i.bak -p -e 's/^4\$/4444/' file &&
-	perl -i.bak -p -e 's/^7\$/7777/' file &&
+	sed -e 's/^4\$/4444/' \
+	    -e 's/^7\$/7777/' \
+		<file >file.munged &&
+	mv file.munged file &&
 	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
 	git commit -m '4 => 4444, 7 => 7777' file &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 12/20] t: refactor tests depending on Perl to print data
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (10 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
                     ` (7 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A bunch of tests rely on Perl to print data in various different ways.
These usages fall into the following categories:

  - Print data conditionally by matching patterns. These usecases can be
    converted to use awk(1) rather easily.

  - Print data repeatedly. These usecases can typically be converted to
    use a combination of `test-tool genzeros` and sed(1).

  - Print data in reverse. These usecases can be converted to use
    awk(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0610-reftable-basics.sh          |  7 +++----
 t/t0613-reftable-write-options.sh   |  4 ++--
 t/t1010-mktree.sh                   |  8 ++++----
 t/t4150-am.sh                       | 10 +++++-----
 t/t5300-pack-object.sh              | 16 +++++-----------
 t/t5326-multi-pack-bitmaps.sh       |  6 +++---
 t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------
 t/t5410-receive-pack-alternates.sh  |  6 +++---
 t/t5701-git-serve.sh                |  7 +++++--
 t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------
 t/t6115-rev-list-du.sh              |  8 +-------
 t/t7006-pager.sh                    |  8 ++++----
 t/t8002-blame.sh                    |  2 +-
 t/t9850-shell.sh                    |  4 ++--
 14 files changed, 51 insertions(+), 67 deletions(-)

diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 5e0a1fa176d..77ed11e7172 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
+test_expect_success 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+
+	awk "BEGIN { for (i = 0; i < 50000; i++) printf \"%s\", \"this is a long commit message\" }" >commit-msg &&
 	git -C repo commit --allow-empty --file=../commit-msg
 '
 
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index fa1e2f9eef8..42aa1592f87 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
+test_expect_success 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
 		cd repo &&
 		test_commit A &&
-		perl -e "print \"a\" x 500" >logmsg &&
+		test-tool genzeros 500 | tr "\000" "a" >logmsg &&
 		cat >expect <<-EOF &&
 		fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large
 		EOF
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 4977998e205..e9973f74949 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
-	perl -e "print reverse <>" <top |
+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+	sort -r <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
-	perl -e "print reverse <>" <top.withsub |
+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+	sort -r <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
 '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 4794510d70d..2ae93d3c967 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
+test_expect_success 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'
     Body test" --author="$LONG <long@example.com>" &&
 	git format-patch --stdout -1 >patch &&
 	# bump from, date, and subject down to in-body header
-	perl -lpe "
-		if (/^From:/) {
+	awk "
+		/^From:/{
 			print \"From: x <x\@example.com>\";
 			print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
 			print \"Subject: x\n\";
-		}
-	" patch >msg &&
+		}; 1
+	" <patch >msg &&
 	git checkout HEAD^ &&
 	git am msg &&
 	# Ensure that the author and full message are present
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 143856c29f1..362b05441af 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,17 +7,11 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pack-object tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	rm -f .git/index* &&
-	perl -e "print \"a\" x 4096;" >a &&
-	perl -e "print \"b\" x 4096;" >b &&
-	perl -e "print \"c\" x 4096;" >c &&
+	test-tool genzeros 4096 | tr "\000" "a" >a &&
+	test-tool genzeros 4096 | tr "\000" "b" >b &&
+	test-tool genzeros 4096 | tr "\000" "c" >c &&
 	test-tool genrandom "seed a" 2097152 >a_big &&
 	test-tool genrandom "seed b" 2097152 >b_big &&
 	git update-index --add a a_big b b_big c &&
@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'
 # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>
 # e.g.: check_deltas stderr -gt 0
 check_deltas() {
-	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' <"$1") &&
 	shift &&
 	if ! test "$deltas" "$@"
 	then
@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '
 	check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
 '
 
-test_expect_success 'compare delta flavors' '
+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '
 	perl -e '\''
 		defined($_ = -s $_) or die for @ARGV;
 		exit 1 if $ARGV[0] <= $ARGV[1];
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 627f8b4efdc..e5d52de4bd3 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {
 			comm -13 bitmaps commits >before &&
 			test_line_count = 1 before &&
 
-			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
-				<before | git update-ref --stdin &&
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
+			git update-ref --stdin &&
 
 			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
 			rm -fr $midx &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 1059ff45fe4..df13a18c5c7 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
-	test_done
-fi
-
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {
 
 tag_everything () {
 	git rev-list --all --no-object-names >in &&
-	perl -lne '
-		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
-	' <in | git update-ref --stdin
+	sed 's|\(.*\)|create refs/tags/\1 \1|' <in |
+	git update-ref --stdin
 }
 
 test_expect_success 'setup' '
@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '
 	test_cmp expect actual
 '
 
-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
 	test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
 	test_config bitmapPseudoMerge.test.maxMerges 1 &&
 	test_config bitmapPseudoMerge.test.stableThreshold never &&
@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 			test_commit_bulk 16 &&
 
 			git rev-list HEAD~16.. >in &&
-
-			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" <in |
 			git update-ref --stdin || return 1
 		done &&
 
@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 		do
 			test_pseudo_merge_commits $m >oids &&
 			grep -f oids refs |
-			perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
+			sed -n "s|refs/remotes/\([0-9][0-9]*\)/|\1|p" &&
 			sort -u || return 1
 		done >remotes &&
 
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 6a009fdcd71..4e82fd102e3 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -17,10 +17,10 @@ test_expect_success 'setup' '
 '
 
 extract_haves () {
-	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+	depacketize | sed -n 's/^\([^ ][^ ]*\) \.have/\1/p'
 }
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
+test_expect_success 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
+test_expect_success 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 200bf06ecb3..d4c28bae39e 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
+test_expect_success 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 		echo command=ls-refs &&
 		echo object-format=$(test_oid algo) &&
 		echo 0001 &&
-		perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
+		awk "{
+			for (i = 1; i <= 65536; i++)
+				print \"ref-prefix refs/heads/\", \$i
+		}" &&
 		echo 0000
 	} |
 	test-tool pkt-line pack >in &&
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 8074185742c..273196f52b5 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
-	git rev-list --parents --full-history main -- foo |
-		perl -e "print reverse <>" > expected &&
+reverse () {
+	awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'
+}
+
+test_expect_success '--reverse --parents --full-history combines correctly' '
+	git rev-list --parents --full-history main -- foo | reverse >expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
 		> actual &&
 	test_cmp expected actual
 	'
 
-test_expect_success PERL_TEST_HELPERS '--boundary does too' '
-	git rev-list --boundary --parents --full-history main ^root -- foo |
-		perl -e "print reverse <>" > expected &&
+test_expect_success '--boundary does too' '
+	git rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&
 	git rev-list --boundary --reverse --parents --full-history \
 		main ^root -- foo > actual &&
 	test_cmp expected actual
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 6a74be576a2..04c577dad69 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list disk usage tests; Perl not available'
-	test_done
-fi
-
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '
 disk_usage_slow () {
 	git rev-list --no-object-names "$@" |
 	git cat-file --batch-check="%(objectsize:disk)" |
-	perl -lne '$total += $_; END { print $total}'
+	awk '{ i += $1 } END { print i }'
 }
 
 # check behavior with given rev-list options; note that
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 49aae183829..9717e825f0d 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success PERL_TEST_HELPERS 'setup large log output' '
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+test_expect_success 'setup large log output' '
+	test-tool genzeros 50000 |
+	tr "\000" "a" |
+	sed "s/a/this is a long commit message/g" >commit-msg &&
 	git commit --allow-empty -F commit-msg
 '
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index b40199df231..0b7548c8e75 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '
 		expect=$1 && shift &&
 		echo $sha1 | cut -c 1-$expect >expect &&
 		git blame "$@" abbrev.t >actual &&
-		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" <actual >actual.sha &&
 		test_cmp expect actual.sha
 	}
 '
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index f619b60f226..21c3af48bd0 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
-	perl -e "print \"a\" x 2**12 for (0..2**19)" |
+test_expect_success 'shell complains of overlong commands' '
+	test-tool genzeros | tr "\000" "a" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (11 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
                     ` (6 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of tests that depend on Perl for textconv scripts.
Refactor these tests to instead be implemented via shell utilities so
that we can drop a couple of PERL_TEST_HELPERS prerequisites.

Note that not all of the conversions are a one-to-one equivalent to the
previous textconv scripts. But that's not really needed in the first
place: we only care that the textconv script does something, and that
can be verified trivially without having a full-blown invocation of
hexdump. So at times, the implementation of the textconv scripts is
reduced to their bare minimum and the expectations of those tests are
adapted accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t4030-diff-textconv.sh       | 15 +++------------
 t/t4031-diff-rewrite-binary.sh | 19 +++++++------------
 t/t7815-grep-binary.sh         | 15 +++------------
 3 files changed, 13 insertions(+), 36 deletions(-)

diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index c7d8eb12453..f904fc19f69 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping diff textconv tests; Perl not available'
-	test_done
-fi
-
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
 +1
 EOF
 
-cat >hexdump <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-chmod +x hexdump
-
 test_expect_success 'setup binary file with history' '
+	write_script hexdump <<-\EOF &&
+	tr "\000\001" "01" <"$1"
+	EOF
 	test_commit --printf one file "\\0\\n" &&
 	test_commit --printf --append two file "\\01\\n"
 '
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index cbe50b15772..15e012ccc7c 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
 	grep " rewrite file" diff
 '
 
-{
-	echo "#!$SHELL_PATH"
-	cat <<'EOF'
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-} >dump
-chmod +x dump
-
 test_expect_success 'setup textconv' '
+	write_script dump <<-\EOF &&
+	test-tool hexdump <"$1"
+	EOF
 	echo file diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
+test_expect_success 'rewrite diff respects textconv' '
 	git diff -B >diff &&
-	grep "dissimilarity index" diff &&
-	grep "^-61" diff &&
-	grep "^-0" diff
+	test_grep "dissimilarity index" diff &&
+	test_grep "^-3d 0a 00" diff &&
+	test_grep "^+3d 0a 01" diff
 '
 
 test_done
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index b2730d200c8..3bd91da9707 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,12 +4,6 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping grep binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
 	test_cmp expect actual
 '
 
-cat >nul_to_q_textconv <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
-EOF
-chmod +x nul_to_q_textconv
-
 test_expect_success 'setup textconv filters' '
+	write_script nul_to_q_textconv <<-\EOF &&
+	tr "\000" "Q" <"$1"
+	EOF
 	echo a diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (12 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
                     ` (5 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
stdin. Refactor it to instead use awk(1) so that we drop the
PERL_TEST_HELPERS prerequisite in users of this library.

Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
now that the test suite doesn't bail out early anymore in case the
prerequisite isn't set.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-gpg.sh            |  6 +-----
 t/t6300-for-each-ref.sh | 21 ++++++++++-----------
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 3845b6ac449..937b876bd05 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '
 '
 
 sanitize_pgp() {
-	perl -ne '
-		/^-----END PGP/ and $in_pgp = 0;
-		print unless $in_pgp;
-		/^-----BEGIN PGP/ and $in_pgp = 1;
-	'
+	sed "/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}"
 }
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 732a4d3171e..5db7038c417 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping for-each-ref tests; Perl not available'
-	test_done
-fi
-
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '
 	test_must_fail git for-each-ref --format="%(raw)" --tcl
 '
 
-test_expect_success '%(raw) with --perl' '
+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
 	git for-each-ref --format="\$name= %(raw);
 print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
 	cmp blob1 actual &&
@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '
 '
 
 test_trailer_option () {
+	if test "$#" -eq 3
+	then
+		prereq="$1"
+		shift
+	fi &&
 	title=$1 option=$2
 	cat >expect
-	test_expect_success "$title" '
+	test_expect_success $prereq "$title" '
 		git for-each-ref --format="%($option)" refs/heads/main >actual &&
 		test_cmp expect actual &&
 		git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
@@ -1452,7 +1451,7 @@ test_trailer_option () {
 	'
 }
 
-test_trailer_option '%(trailers:unfold) unfolds trailers' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
 	'trailers:unfold' <<-EOF
 	$(unfold <trailers)
 
@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \
 
 	EOF
 
-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
 	'trailers:only,unfold' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 
 	EOF
 
-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
 	'trailers:unfold,only' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (13 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
                     ` (4 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `name_from_description()` test helper uses Perl to munge a given
description and convert it into a name. Refactor it to instead use a
combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
prerequisites in users of this library.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-t6000.sh                 | 13 ++++++-------
 t/t6002-rev-list-bisect.sh     |  6 ------
 t/t6003-rev-list-topo-order.sh |  6 ------
 3 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
index fba6778ca35..35c54724650 100644
--- a/t/lib-t6000.sh
+++ b/t/lib-t6000.sh
@@ -109,13 +109,12 @@ check_output () {
 # All alphanums translated into -'s which are then compressed and stripped
 # from front and back.
 name_from_description () {
-	perl -pe '
-		s/[^A-Za-z0-9.]/-/g;
-		s/-+/-/g;
-		s/-$//;
-		s/^-//;
-		y/A-Z/a-z/;
-	'
+	sed \
+		-e 's/[^A-Za-z0-9.]/-/g' \
+		-e 's/--*/-/g' \
+		-e 's/-$//' \
+		-e 's/^-//' \
+		-e 'y/A-Z/a-z/'
 }
 
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index 5e1482aff78..daa009c9a1b 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list bisect tests; Perl not available'
-	test_done
-fi
-
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 02dd4127aff..0d7055d46d4 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list topo-order tests; Perl not available'
-	test_done
-fi
-
 list_duplicates()
 {
     "$@" | sort | uniq -d

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 16/20] t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (14 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
                     ` (3 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our Apache HTTPD setup exposes an "one_time_perl" endpoint to access
repositories. If used, we execute the "apply-one-time-perl.sh" CGI
script that checks whether we have a "one-time-perl" script. If so, that
script gets executed so that it can munge what would be served. Once
done, the script gets removed so that it doesn't execute a second time.

As the name says, this functionality expects the user to pass a Perl
script. This isn't really necessary though: we can just as easily
implement the same thing with arbitrary scripts.

Refactor the code so that we instead expect an arbitrary script to
exist and rename the functionality to "one-time-script". Adapt callers
to use shell utilities instead of Perl so that we can drop the
PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-httpd.sh                       |  2 +-
 t/lib-httpd/apache.conf              |  6 ++---
 t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------
 t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++
 t/t5537-fetch-shallow.sh             | 17 ++++++-------
 t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------
 t/t5702-protocol-v2.sh               | 27 +++++++++++---------
 t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---
 8 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index d83bafeab32..5091db949b7 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -165,7 +165,7 @@ prepare_httpd() {
 	install_script broken-smart-http.sh
 	install_script error-smart-http.sh
 	install_script error.sh
-	install_script apply-one-time-perl.sh
+	install_script apply-one-time-script.sh
 	install_script nph-custom-auth.sh
 
 	ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 022276a6b9a..e631ab0eb5e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
-<LocationMatch /one_time_perl/>
+<LocationMatch /one_time_script/>
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1
 ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Directory ${GIT_EXEC_PATH}>
 	Options FollowSymlinks
@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Files error.sh>
   Options ExecCGI
 </Files>
-<Files apply-one-time-perl.sh>
+<Files apply-one-time-script.sh>
 	Options ExecCGI
 </Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
deleted file mode 100644
index d7f9fed6aee..00000000000
--- a/t/lib-httpd/apply-one-time-perl.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# If "one-time-perl" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,
-# using the contents of "one-time-perl" as the perl command to be run. If the
-# response was modified as a result, delete "one-time-perl" so that subsequent
-# HTTP responses are no longer modified.
-#
-# This can be used to simulate the effects of the repository changing in
-# between HTTP request-response pairs.
-if test -f one-time-perl
-then
-	LC_ALL=C
-	export LC_ALL
-
-	"$GIT_EXEC_PATH/git-http-backend" >out
-	"$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
-
-	if cmp -s out out_modified
-	then
-		cat out
-	else
-		cat out_modified
-		rm one-time-perl
-	fi
-else
-	"$GIT_EXEC_PATH/git-http-backend"
-fi
diff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh
new file mode 100644
index 00000000000..b1682944e28
--- /dev/null
+++ b/t/lib-httpd/apply-one-time-script.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# If "one-time-script" exists in $HTTPD_ROOT_PATH, run the script on the HTTP
+# response. If the response was modified as a result, delete "one-time-script"
+# so that subsequent HTTP responses are no longer modified.
+#
+# This can be used to simulate the effects of the repository changing in
+# between HTTP request-response pairs.
+if test -f one-time-script
+then
+	LC_ALL=C
+	export LC_ALL
+
+	"$GIT_EXEC_PATH/git-http-backend" >out
+	./one-time-script out >out_modified
+
+	if cmp -s out out_modified
+	then
+		cat out
+	else
+		cat out_modified
+		rm one-time-script
+	fi
+else
+	"$GIT_EXEC_PATH/git-http-backend"
+fi
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 77d20d19110..9dfcfb46df0 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before
 	git -C "$REPO" config protocol.version 2 &&
 	git -C client config protocol.version 2 &&
 
-	git -C client fetch --depth=2 "$HTTPD_URL/one_time_perl/repo" main:a_branch &&
+	git -C client fetch --depth=2 "$HTTPD_URL/one_time_script/repo" main:a_branch &&
 
 	# Craft a situation in which the server sends back an unshallow request
 	# with an empty packfile. This is done by refetching with a shorter
 	# depth (to ensure that the packfile is empty), and overwriting the
 	# shallow line in the response with the unshallow line we want.
-	printf "$(test_oid perl)" \
-	       "$(git -C "$REPO" rev-parse HEAD)" \
-	       "$(git -C "$REPO" rev-parse HEAD^)" \
-	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" <"\$1"
+	EOF
 	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
-		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
+		fetch --depth=1 "$HTTPD_URL/one_time_script/repo" \
 		main:a_branch &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl" &&
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script" &&
 
 	# Ensure that the resulting repo is consistent, despite our failure to
 	# fetch.
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index bc7e0fec8dc..f878592a377 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -737,21 +737,25 @@ intersperse () {
 	sed 's/\(..\)/'$1'\1/g'
 }
 
-# Create a one-time-perl command to replace the existing packfile with $1.
+# Create a one-time-script command to replace the existing packfile with $1.
 replace_packfile () {
-	# The protocol requires that the packfile be sent in sideband 1, hence
-	# the extra \x01 byte at the beginning.
-	cp $1 "$HTTPD_ROOT_PATH/one-time-pack" &&
-	echo 'if (/packfile/) {
-		print;
-		my $length = -s "one-time-pack";
-		printf "%04x\x01", $length + 5;
-		print `cat one-time-pack` . "0000";
-		last
-	}' >"$HTTPD_ROOT_PATH/one-time-perl"
+	cp "$1" one-time-pack &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	if grep packfile "\$1" >/dev/null
+	then
+		sed '/packfile/q' <"\$1" &&
+		# The protocol requires that the packfile be sent in sideband
+		# 1, hence the extra \001 byte at the beginning.
+		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
+		cat "$PWD/one-time-pack" &&
+		printf "0000"
+	else
+		cat "\$1"
+	fi
+	EOF
 }
 
-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
+test_expect_success 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t
 	# section header.
 	test_config -C "$SERVER" protocol.version 2 &&
 	test_must_fail git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&
 
 	test_grep "did not send all necessary objects" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not
 
 	# Exercise to make sure it works.
 	git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&
 	! grep "missing object referenced by" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 
 	# Clone. The client has deltabase_have but not deltabase_missing.
 	git -c protocol.version=2 clone --no-checkout \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo &&
 	git -C repo hash-object -w -- "$SERVER/have.txt" &&
 
 	# Sanity check to ensure that the client does not have
@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 	grep "want $(cat deltabase_missing)" trace &&
 	! grep "want $(cat deltabase_have)" trace &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 # DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ad5e772cd72..27434b1f07a 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
+test_expect_success 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM'
 
 	# After "ready" in the acknowledgments section, pretend that a FLUSH
 	# (0000) was sent instead of a DELIM (0001).
-	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/ready/{n;s/0001/0000/;}" <"$1"
+	EOF
 
 	test_must_fail git -C http_child -c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
+test_expect_success 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect
 
 	# After the acknowledgments section, pretend that a DELIM
 	# (0001) was sent instead of a FLUSH (0000).
-	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/acknowledgments/,//{s/0000/0001/;}" <"$1"
+	EOF
 
 	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
 		-c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	grep "fetch< .*acknowledgments" log &&
 	! grep "fetch< .*ready" log &&
 	test_grep "expected no other sections to be sent after no .ready." err
@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
-	URI="$HTTPD_URL/one_time_perl/server" &&
+	URI="$HTTPD_URL/one_time_script/server" &&
 
 	setup_negotiate_only "$SERVER" "$URI" &&
 
-	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" <"$1"
+	EOF
 
 	test_must_fail git -c protocol.version=2 -C client fetch \
 		--no-tags \
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index f59d47aa6c6..ac7266126a0 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '
 		test_commit m3 &&
 		git tag -d m2 m3
 	) &&
-	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo" &&
+	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo" &&
 	git -C "$LOCAL_PRISTINE" config protocol.version 2
 '
 
@@ -481,7 +481,9 @@ inconsistency () {
 	# RPCs during a single negotiation.
 	oid1=$(git -C "$REPO" rev-parse $1) &&
 	oid2=$(git -C "$REPO" rev-parse $2) &&
-	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	sed "s/$oid1/$oid2/" <"\$1"
+	EOF
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
-	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/main/rain/" <"$1"
+	EOF
 	test_must_fail git -C local fetch 2>err &&
 
 	test_grep "fatal: remote error: unknown ref refs/heads/rain" err

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (15 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
                     ` (2 subsequent siblings)
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `generate_random_characters()` helper function generates N
random characters in the range 'a-z' and writes them into a file. The
logic currently uses Perl, but it can be adapted rather easily by:

  - Making `test-tool genrandom` generate an infinite stream.

  - Using `tr -dc` to strip all characters which aren't in the range of
    'a-z'.

  - Using `test_copy_bytes()` to copy the first N bytes.

This allows us to drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 4a892a91780..bf10d253ec4 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -20,8 +20,7 @@ EOF
 generate_random_characters () {
 	LEN=$1
 	NAME=$2
-	test-tool genrandom some-seed $LEN |
-		perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
+	test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME"
 }
 
 filter_git () {
@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
+test_expect_success 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
+test_expect_success 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 18/20] t0210: refactor trace2 scrubbing to not use Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (16 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 20/20] t5703: refactor test " Patrick Steinhardt
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The output generated by our trace2 mechanism contains several fields
that are dependent on the environment they're being run in, which makes
it somewhat harder to test it. As a countermeasure we scrub the output
and strip out any fields that contain such information.

The logic to do so is implemented in Perl, but it can be trivially
ported to instead use sed(1). Refactor the code accordingly so that we
can drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------
 t/t0210/scrub_normal.perl | 54 -----------------------------------------
 2 files changed, 43 insertions(+), 72 deletions(-)

diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index ba4c0442b85..96c68f65df2 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping trace2 tests; Perl not available'
-	test_done
-fi
-
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF
 #
 # Implicit return from cmd_<verb> function propagates <code>.
 
+scrub_normal () {
+	# Scrub the variable fields from the normal trace2 output to make
+	# testing easier:
+	#
+	#   1. Various messages include an elapsed time in the middle of the
+	#      message. Replace the time with a placeholder to simplify our
+	#      HEREDOC in the test script.
+	#
+	#   2. We expect:
+	#
+	#        start <argv0> [<argv1> [<argv2> [...]]]
+	#
+	#      where argv0 might be a relative or absolute path, with or
+	#      without quotes, and platform dependent. Replace argv0 with a
+	#      token for HEREDOC matching in the test script.
+	#
+	#   3. Likewise, the 'cmd_path' message breaks out argv[0].
+	#
+	#      This line is only emitted when RUNTIME_PREFIX is defined,
+	#      so just omit it for testing purposes.
+	#
+	#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's
+	#      sake, skip it when parsing normal.
+	sed \
+		-e 's/elapsed:[0-9]*\.[0-9][0-9]*\([eE][-+]\{0,1\}[0-9][0-9]*\)\{0,1\}/elapsed:_TIME_/g' \
+		-e "s/^start '[^']*' \(.*\)/start _EXE_ \1/" \
+		-e 's/^start [^ ][^ ]* \(.*\)/start _EXE_ \1/' \
+		-e '/^cmd_path/d' \
+		-e '/^cmd_ancestry/d'
+}
+
 test_expect_success 'normal stream, return code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '
 test_expect_success 'normal stream, return code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 1
@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '
 	test_when_finished "rm -r traces actual expect" &&
 	mkdir traces &&
 	GIT_TRACE2="$(pwd)/traces" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <"$(ls traces/*)" >actual &&
+	scrub_normal <"$(ls traces/*)" >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '
 test_expect_success 'normal stream, exit code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 0
@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '
 test_expect_success 'normal stream, exit code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 1
@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '
 test_expect_success 'normal stream, error event' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\''
@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '
 test_expect_success 'BUG messages are written to trace2' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 007bug &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 007bug
@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 008bug
@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 009bug_BUG
@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 010bug_BUG
@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '
 	test_config_global trace2.normalBrief 1 &&
 	test_config_global trace2.normalTarget "$(pwd)/trace.normal" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '
 	mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" &&
 	test_config_global include.path "$(pwd)/real.gitconfig" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl
deleted file mode 100644
index 7cc4de392a0..00000000000
--- a/t/t0210/scrub_normal.perl
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/perl
-#
-# Scrub the variable fields from the normal trace2 output to
-# make testing easier.
-
-use strict;
-use warnings;
-
-my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?';
-
-# This code assumes that the trace2 data was written with bare
-# turned on (which omits the "<clock> <file>:<line>" prefix.
-
-while (<>) {
-    # Various messages include an elapsed time in the middle
-    # of the message.  Replace the time with a placeholder to
-    # simplify our HEREDOC in the test script.
-    s/elapsed:$float/elapsed:_TIME_/g;
-
-    my $line = $_;
-
-    # we expect:
-    #    start <argv0> [<argv1> [<argv2> [...]]]
-    #
-    # where argv0 might be a relative or absolute path, with
-    # or without quotes, and platform dependent.  Replace argv0
-    # with a token for HEREDOC matching in the test script.
-
-    if ($line =~ m/^start/) {
-	$line =~ /^start\s+(.*)/;
-	my $argv = $1;
-	$argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/;
-	my $argv_0 = $1;
-	my $argv_rest = $2;
-
-	print "start _EXE_ $argv_rest\n";
-    }
-    elsif ($line =~ m/^cmd_path/) {
-	# Likewise, the 'cmd_path' message breaks out argv[0].
-	#
-	# This line is only emitted when RUNTIME_PREFIX is defined,
-	# so just omit it for testing purposes.
-	# print "cmd_path _EXE_\n";
-    }
-    elsif ($line =~ m/^cmd_ancestry/) {
-	# 'cmd_ancestry' is not implemented everywhere, so for portability's
-	# sake, skip it when parsing normal.
-	#
-	# print "$line";
-    }
-    else {
-	print "$line";
-    }
-}

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 19/20] t5316: refactor `max_chain()` to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (17 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  2025-03-25 13:14   ` [PATCH v2 20/20] t5703: refactor test " Patrick Steinhardt
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `max_chain()` helper function is used to extract the maximum delta
chain of a packfile as printed by git-index-pack(1). The script uses
Perl to extract that data, but it can be trivially refactored to use
awk(1) instead.

Refactor the helper accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5316-pack-delta-depth.sh | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index cd947b5a5ef..defaa06d650 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '
 
 max_chain() {
 	git index-pack --verify-stat-only "$1" >output &&
-	perl -lne '
-	  BEGIN { $len = 0 }
-	  /chain length = (\d+)/ and $len = $1;
-	  END { print $len }
-	' output
+	awk '
+		BEGIN { len=0 }
+		/chain length = [0-9]+:/{ len=$4 }
+		END { print len }
+	' <output | tr -d ':'
 }
 
 # Note that this whole setup is pretty reliant on the current
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
+test_expect_success 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
+test_expect_success '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
+test_expect_success '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
+test_expect_success 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v2 20/20] t5703: refactor test to not depend on Perl
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (18 preceding siblings ...)
  2025-03-25 13:14   ` [PATCH v2 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
@ 2025-03-25 13:14   ` Patrick Steinhardt
  19 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-25 13:14 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We use Perl due to two different reasons in t5703:

  - To filter advertised capabilities.

  - To set up a CGI script with HTTPD.

Refactor the first category to use `test_grep` instead. Refactoring the
second category would be a bit more involved, so instead we add the
PERL_TEST_HELPERS prerequisite to those individual tests now.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index ac7266126a0..1ab3191d72d 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
-	test_done
-fi
-
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '
 
 test_expect_success 'config controls ref-in-want advertisement' '
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant false &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant true &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_file_not_empty out.filter
+	test_grep "ref-in-want" out
 '
 
 test_expect_success 'invalid want-ref line' '
@@ -486,7 +477,7 @@ inconsistency () {
 	EOF
 }
 
-test_expect_success 'server is initially ahead - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
 	test_grep "fatal: remote error: upload-pack: not our ref" err
 '
 
-test_expect_success 'server is initially ahead - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server loses a ref - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-25 13:14   ` [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-03-25 14:35     ` Phillip Wood
  2025-03-27 10:19       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Phillip Wood @ 2025-03-25 14:35 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak

Hi Patrick

On 25/03/2025 13:14, Patrick Steinhardt wrote:
>   broken_c_unquote () {
> -	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
> +	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
>   }
>   
>   broken_c_unquote_verbose () {
> -	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
> +	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
>   }

Thanks for removing the redirection here, unfortunately there are still 
a whole bunch of needless input redirections below.

Best Wishes

Phillip

>   stderr_contains () {
> diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
> index a92a42990b1..db75998e35f 100755
> --- a/t/t4029-diff-trailing-space.sh
> +++ b/t/t4029-diff-trailing-space.sh
> @@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
>   EOF
>   exit 1
>   
> -test_expect_success PERL_TEST_HELPERS "$test_description" '
> +test_expect_success "$test_description" '
>   	printf "\nx\n" > f &&
>   	before=$(git hash-object f) &&
>   	before=$(git rev-parse --short $before) &&
> @@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
>   	git config --bool diff.suppressBlankEmpty true &&
>   	git diff f > actual &&
>   	test_cmp exp actual &&
> -	perl -i.bak -p -e "s/^\$/ /" exp &&
> +	sed "s/^\$/ /" <exp >exp.munged &&

> +	mv exp.munged exp &&
>   	git config --bool diff.suppressBlankEmpty false &&
>   	git diff f > actual &&
>   	test_cmp exp actual &&
> diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
> index 7fcca9ddad5..bacb93d014f 100755
> --- a/t/t4200-rerere.sh
> +++ b/t/t4200-rerere.sh
> @@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping rerere tests; Perl not available'
> -	test_done
> -fi
> -
>   test_expect_success 'setup' '
>   	cat >a1 <<-\EOF &&
>   	Some title
> @@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
>   	test_might_fail git config --unset rerere.enabled &&
>   	test_must_fail git merge first &&
>   
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1 &&
>   	grep "^=======\$" $rr/preimage &&
>   	! test -f $rr/postimage &&
> @@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
>   	git reset --hard &&
>   	test_must_fail git merge first &&
>   
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1 &&
>   	grep ^=======$ $rr/preimage
>   '
> @@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
>   	git config rerere.enabled true &&
>   	git reset --hard &&
>   	test_must_fail git merge first &&
> -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
> +	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>   	rr=.git/rr-cache/$sha1
>   '
>   
> diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
> index ac5e370e1e4..07382797bbb 100755
> --- a/t/t5303-pack-corruption-resilience.sh
> +++ b/t/t5303-pack-corruption-resilience.sh
> @@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
>   	git cat-file blob $blob_3 > /dev/null
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
> +test_expect_success 'create corruption in data of first object' '
>   	create_new_pack &&
>   	git prune-packed &&
>   	chmod +w ${pack}.pack &&
> -	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
> +	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
> +	mv ${pack}.pack.munged ${pack}.pack &&
>   	test_must_fail git cat-file blob $blob_1 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_3 > /dev/null
> @@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
>   	git cat-file blob $blob_3 > /dev/null
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
> +test_expect_success 'create corruption in data of first delta' '
>   	create_new_pack &&
>   	git prune-packed &&
>   	chmod +w ${pack}.pack &&
> -	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
> +	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
> +	mv ${pack}.pack.munged ${pack}.pack &&
>   	git cat-file blob $blob_1 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>   	test_must_fail git cat-file blob $blob_3 > /dev/null
> diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
> index 81987296235..9033d72b8c7 100755
> --- a/t/t5310-pack-bitmaps.sh
> +++ b/t/t5310-pack-bitmaps.sh
> @@ -395,7 +395,7 @@ test_bitmap_cases () {
>   		)
>   	'
>   
> -	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
> +	test_expect_success 'pack.preferBitmapTips' '
>   		git init repo &&
>   		test_when_finished "rm -fr repo" &&
>   		(
> @@ -421,7 +421,7 @@ test_bitmap_cases () {
>   
>   			# mark the commits which did not receive bitmaps as preferred,
>   			# and generate the bitmap again
> -			perl -pe "s{^}{create refs/tags/include/$. }" <before |
> +			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
>   				git update-ref --stdin &&
>   			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
>   
> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
> index 342d0423c92..d5c0d00114e 100755
> --- a/t/t5534-push-signed.sh
> +++ b/t/t5534-push-signed.sh
> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
>   	test_cmp expect dst/push-cert-status
>   '
>   
> -test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
> +test_expect_success GPG 'inconsistent push options in signed push not allowed' '
>   	# First, invoke receive-pack with dummy input to obtain its preamble.
>   	prepare_dst &&
>   	git -C dst config receive.certnonceseed sekrit &&
> @@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
>   	# Tweak the push output to make the push option outside the cert
>   	# different, then replay it on a fresh dst, checking that ff is not
>   	# deleted.
> -	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
> +	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
>   	prepare_dst &&
>   	git -C dst config receive.certnonceseed sekrit &&
>   	git -C dst config receive.advertisepushoptions 1 &&
> diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
> index 6131c361094..12329aab388 100755
> --- a/t/t6011-rev-list-with-bad-commit.sh
> +++ b/t/t6011-rev-list-with-bad-commit.sh
> @@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping rev-list with bad commit tests; Perl not available'
> -	test_done
> -fi
> -
>   # Note:
>   # - compression level is set to zero to make "corruptions" easier to perform
>   # - reflog is disabled to avoid extra references which would twart the test
> @@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
>      first_commit=$(git rev-parse HEAD~3)
>      '
>   
> -test_expect_success 'corrupt second commit object' \
> -   '
> -   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
> -   test_must_fail git fsck --full
> -   '
> +test_expect_success 'corrupt second commit object' '
> +	for p in .git/objects/pack/*.pack
> +	do
> +		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
> +		mv "$p.munged" "$p" ||
> +		return 1
> +	done &&
> +	test_must_fail git fsck --full
> +'
>   
>   test_expect_success 'rev-list should fail' '
>   	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
> diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
> index 14069600a2f..00b81d349b9 100755
> --- a/t/t7416-submodule-dash-url.sh
> +++ b/t/t7416-submodule-dash-url.sh
> @@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping submodule dash URL tests; Perl not available'
> -	test_done
> -fi
> -
>   test_expect_success 'setup' '
>   	git config --global protocol.file.allow always
>   '
> @@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
>   '
>   
>   test_expect_success 'remove ./ protection from .gitmodules url' '
> -	perl -i -pe "s{\./}{}" .gitmodules &&
> +	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
> +	mv .gitmodules.munged .gitmodules &&
>   	git commit -am "drop protection"
>   '
>   
> diff --git a/t/t7508-status.sh b/t/t7508-status.sh
> index 14c41b2cb7c..cdc1d6fcc78 100755
> --- a/t/t7508-status.sh
> +++ b/t/t7508-status.sh
> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
>   	test_cmp expect output
>   '
>   
> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
> +test_expect_success 'status -z implies porcelain' '
>   	git status --porcelain |
> -	perl -pe "s/\012/\000/g" >expect &&
> +	tr "\012" "\000" >expect &&
>   	git status -z >output &&
>   	test_cmp expect output
>   '
> diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
> index 5cb16872081..810dac18f56 100755
> --- a/t/t8006-blame-textconv.sh
> +++ b/t/t8006-blame-textconv.sh
> @@ -4,12 +4,6 @@ test_description='git blame textconv support'
>   
>   . ./test-lib.sh
>   
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping blame textconv tests; Perl not available'
> -	test_done
> -fi
> -
>   find_blame() {
>   	sed -e 's/^[^(]*//'
>   }
> @@ -17,7 +11,7 @@ find_blame() {
>   cat >helper <<'EOF'
>   #!/bin/sh
>   grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
> -"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
> +sed 's/^bin: /converted: /' <"$1"
>   EOF
>   chmod +x helper
>   
> diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
> index a9d38be997c..9afdb45b1cc 100755
> --- a/t/t9137-git-svn-dcommit-clobber-series.sh
> +++ b/t/t9137-git-svn-dcommit-clobber-series.sh
> @@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
>   	test -e file
>   	'
>   
> -test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
> +test_expect_success '(supposedly) non-conflicting change from SVN' '
>   	test x"$(sed -n -e 58p < file)" = x58 &&
>   	test x"$(sed -n -e 61p < file)" = x61 &&
>   	svn_cmd co "$svnrepo" tmp &&
>   	(cd tmp &&
> -		perl -i.bak -p -e "s/^58$/5588/" file &&
> -		perl -i.bak -p -e "s/^61$/6611/" file &&
> +		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
> +		mv file.munged file &&
>   		poke file &&
>   		test x"$(sed -n -e 58p < file)" = x5588 &&
>   		test x"$(sed -n -e 61p < file)" = x6611 &&
> @@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
>   	git commit -m bye-life life
>   	"
>   
> -test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
> +test_expect_success 'change file but in unrelated area' "
>   	test x\"\$(sed -n -e 4p < file)\" = x4 &&
>   	test x\"\$(sed -n -e 7p < file)\" = x7 &&
> -	perl -i.bak -p -e 's/^4\$/4444/' file &&
> -	perl -i.bak -p -e 's/^7\$/7777/' file &&
> +	sed -e 's/^4\$/4444/' \
> +	    -e 's/^7\$/7777/' \
> +		<file >file.munged &&
> +	mv file.munged file &&
>   	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
>   	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
>   	git commit -m '4 => 4444, 7 => 7777' file &&
> 


^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-25 14:35     ` Phillip Wood
@ 2025-03-27 10:19       ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:19 UTC (permalink / raw)
  To: phillip.wood; +Cc: git, Johannes Schindelin, Eric Sunshine, Karthik Nayak

On Tue, Mar 25, 2025 at 02:35:52PM +0000, Phillip Wood wrote:
> Hi Patrick
> 
> On 25/03/2025 13:14, Patrick Steinhardt wrote:
> >   broken_c_unquote () {
> > -	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
> > +	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
> >   }
> >   broken_c_unquote_verbose () {
> > -	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
> > +	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
> >   }
> 
> Thanks for removing the redirection here, unfortunately there are still a
> whole bunch of needless input redirections below.

Fair. I've scanned through all commits now and replaced every use of
such redirects. Will send out that version soonish.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (20 preceding siblings ...)
  2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
@ 2025-03-27 10:36 ` Patrick Steinhardt
  2025-03-27 10:36   ` [PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
                     ` (21 more replies)
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
  22 siblings, 22 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:36 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi,

while Git was initially building on Perl quite a lot, the significance
of Perl has been dwindling over the years as more and more functionality
was converted into C builtins. Nowadays, an installation with Perl-based
features disabled is almost fully functional, only a handful of features
remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these features really are critical for day-to-day usage of Git,
and most users probably wouldn't even notice if those features were not
installed. Perl is thus very much optional nowadays.

There is one big exception though: it is impossible to run our test
suite without a Perl interpreter, so it is not easily possible to verify
that a Perl-less installation actually works as expected. For most of
the part though our test suite doesn't use all that much Perl, either.
It is present in a couple of critical paths, but those are easy to adapt
to not use Perl anymore.

This is exactly what this patch series does: it refactors a couple of
central parts in our test suite to not use Perl anymore so that it
becomes possible to run most of our tests entirely without Perl. Tests
that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq
so that they only execute when a Perl interpreter is available.

With this patch series, 30342 out of 31358 tests pass, which is around
97% of our tests.

Changes in v2:
  - Improve a couple of conversions based on feedback.
  - Clarify the commit message of the textconv conversion.
  - Fix a copy-paste error when it comes to skipping tests in t4103.
  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im

Changes in v3:
  - Remove more useless indirections for sed(1).
  - Link to v2: https://lore.kernel.org/r/20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (20):
      t: skip chain lint when PERL_PATH is unset
      t: refactor environment sanitization to not use Perl
      t: adapt character translation helpers to not use Perl
      t: adapt `test_copy_bytes()` to not use Perl
      t: adapt `test_readlink()` to not use Perl
      t: introduce PERL_TEST_HELPERS prerequisite
      t: adapt existing PERL prerequisites
      meson: stop requiring Perl when tests are enabled
      Makefile: stop requiring Perl when running tests
      t: refactor tests depending on Perl transliteration operator
      t: refactor tests depending on Perl substitution operator
      t: refactor tests depending on Perl to print data
      t: refactor tests depending on Perl for textconv scripts
      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
      t/lib-t6000: refactor `name_from_description()` to not depend on Perl
      t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
      t0021: refactor `generate_random_characters()` to not depend on Perl
      t0210: refactor trace2 scrubbing to not use Perl
      t5316: refactor `max_chain()` to not depend on Perl
      t5703: refactor test to not depend on Perl

 meson.build                               |  2 +-
 t/Makefile                                | 16 +++++++--
 t/helper/test-path-utils.c                | 13 ++++++++
 t/helper/test-sha1.sh                     |  4 +--
 t/lib-diff.sh                             |  4 +--
 t/lib-gpg.sh                              |  6 +---
 t/lib-httpd.sh                            |  2 +-
 t/lib-httpd/apache.conf                   |  6 ++--
 t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------
 t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++
 t/lib-t6000.sh                            | 13 ++++----
 t/t0008-ignores.sh                        |  4 +--
 t/t0021-conversion.sh                     | 13 ++++----
 t/t0090-cache-tree.sh                     |  4 +--
 t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------
 t/t0210/scrub_normal.perl                 | 54 ------------------------------
 t/t0211-trace2-perf.sh                    |  6 ++++
 t/t0610-reftable-basics.sh                |  5 ++-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       | 16 +++++----
 t/t1007-hash-object.sh                    |  6 ++--
 t/t1010-mktree.sh                         |  4 +--
 t/t1450-fsck.sh                           |  6 ++--
 t/t3300-funny-names.sh                    |  6 ++--
 t/t4013-diff-various.sh                   |  6 ++++
 t/t4014-format-patch.sh                   | 30 ++++++++---------
 t/t4020-diff-external.sh                  |  2 +-
 t/t4029-diff-trailing-space.sh            |  3 +-
 t/t4030-diff-textconv.sh                  |  9 ++---
 t/t4031-diff-rewrite-binary.sh            | 17 ++++------
 t/t4058-diff-duplicates.sh                |  6 ++++
 t/t4103-apply-binary.sh                   |  6 ++--
 t/t4116-apply-reverse.sh                  |  4 +--
 t/t4150-am.sh                             |  8 ++---
 t/t4200-rerere.sh                         |  8 ++---
 t/t4205-log-pretty-formats.sh             |  6 ++--
 t/t4216-log-bloom.sh                      |  8 ++---
 t/t5004-archive-corner-cases.sh           |  6 ++++
 t/t5300-pack-object.sh                    | 10 +++---
 t/t5303-pack-corruption-resilience.sh     |  6 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               | 10 +++---
 t/t5318-commit-graph.sh                   | 12 +++----
 t/t5319-multi-pack-index.sh               | 16 ++++-----
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  4 +--
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  2 +-
 t/t5503-tagfollow.sh                      |  6 ++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++
 t/t5532-fetch-proxy.sh                    |  6 ++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  | 15 ++++-----
 t/t5551-http-fetch-smart.sh               |  7 ++++
 t/t5562-http-backend-content-length.sh    |  6 ++++
 t/t5601-clone.sh                          |  4 +--
 t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------
 t/t5701-git-serve.sh                      |  5 ++-
 t/t5702-protocol-v2.sh                    | 21 +++++++-----
 t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------
 t/t5710-promisor-remote-capability.sh     |  6 ++++
 t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---
 t/t6013-rev-list-reverse-parents.sh       | 10 +++---
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++
 t/t6115-rev-list-du.sh                    |  2 +-
 t/t6300-for-each-ref.sh                   | 15 ++++++---
 t/t7006-pager.sh                          |  6 ++--
 t/t7416-submodule-dash-url.sh             |  3 +-
 t/t7501-commit-basic-functionality.sh     |  6 ++--
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  9 ++---
 t/t8001-annotate.sh                       |  6 ++++
 t/t8002-blame.sh                          |  8 ++++-
 t/t8006-blame-textconv.sh                 |  2 +-
 t/t8011-blame-split-file.sh               |  6 ++--
 t/t8012-blame-colors.sh                   |  6 ++++
 t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib-functions.sh                   | 20 +++--------
 t/test-lib.sh                             | 49 +++++++++++++++++----------
 84 files changed, 471 insertions(+), 373 deletions(-)

Range-diff versus v2:

 1:  8c98b24fe4c =  1:  f2fe08ef0ff t: skip chain lint when PERL_PATH is unset
 2:  f140153954c =  2:  9dd2edd0a1a t: refactor environment sanitization to not use Perl
 3:  94b5591f666 =  3:  c77424e6907 t: adapt character translation helpers to not use Perl
 4:  a5880fdb8ef =  4:  476d1b15932 t: adapt `test_copy_bytes()` to not use Perl
 5:  3b64c99c061 =  5:  14badee2551 t: adapt `test_readlink()` to not use Perl
 6:  a3536260e4c =  6:  9a88a46bd10 t: introduce PERL_TEST_HELPERS prerequisite
 7:  98961b0e065 =  7:  e7413bf28ae t: adapt existing PERL prerequisites
 8:  bbdd1fe6c7c =  8:  581a9bedd22 meson: stop requiring Perl when tests are enabled
 9:  bda7e7922ce =  9:  cfe1797ae74 Makefile: stop requiring Perl when running tests
10:  d95d50c4b73 = 10:  99e678b83a6 t: refactor tests depending on Perl transliteration operator
11:  f5b30cc3f8f ! 11:  93a98d3e3cf t: refactor tests depending on Perl substitution operator
    @@ t/t4029-diff-trailing-space.sh: test_expect_success PERL_TEST_HELPERS "$test_des
      	git diff f > actual &&
      	test_cmp exp actual &&
     -	perl -i.bak -p -e "s/^\$/ /" exp &&
    -+	sed "s/^\$/ /" <exp >exp.munged &&
    ++	sed "s/^\$/ /" exp >exp.munged &&
     +	mv exp.munged exp &&
      	git config --bool diff.suppressBlankEmpty false &&
      	git diff f > actual &&
    @@ t/t4200-rerere.sh: test_expect_success 'activate rerere, old style (conflicting
      	test_must_fail git merge first &&
      
     -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
    -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
    ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
      	rr=.git/rr-cache/$sha1 &&
      	grep "^=======\$" $rr/preimage &&
      	! test -f $rr/postimage &&
    @@ t/t4200-rerere.sh: test_expect_success 'rerere.enabled works, too' '
      	test_must_fail git merge first &&
      
     -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
    -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
    ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
      	rr=.git/rr-cache/$sha1 &&
      	grep ^=======$ $rr/preimage
      '
    @@ t/t4200-rerere.sh: test_expect_success 'set up rr-cache' '
      	git reset --hard &&
      	test_must_fail git merge first &&
     -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
    -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
    ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
      	rr=.git/rr-cache/$sha1
      '
      
    @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and loose copy o
      	git prune-packed &&
      	chmod +w ${pack}.pack &&
     -	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
    -+	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
    ++	sed "s/ base /abcdef/" ${pack}.pack >${pack}.pack.munged &&
     +	mv ${pack}.pack.munged ${pack}.pack &&
      	test_must_fail git cat-file blob $blob_1 > /dev/null &&
      	test_must_fail git cat-file blob $blob_2 > /dev/null &&
    @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and then a repac
      	git prune-packed &&
      	chmod +w ${pack}.pack &&
     -	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
    -+	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
    ++	sed "s/ delta1 /abcdefgh/" ${pack}.pack >${pack}.pack.munged &&
     +	mv ${pack}.pack.munged ${pack}.pack &&
      	git cat-file blob $blob_1 > /dev/null &&
      	test_must_fail git cat-file blob $blob_2 > /dev/null &&
    @@ t/t5310-pack-bitmaps.sh: test_bitmap_cases () {
      			# mark the commits which did not receive bitmaps as preferred,
      			# and generate the bitmap again
     -			perl -pe "s{^}{create refs/tags/include/$. }" <before |
    -+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
    ++			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
      				git update-ref --stdin &&
      			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
      
    @@ t/t5534-push-signed.sh: test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent
      	# different, then replay it on a fresh dst, checking that ff is not
      	# deleted.
     -	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
    -+	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
    ++	sed "s/\([^ ]\)bar/\1baz/" push >push.tweak &&
      	prepare_dst &&
      	git -C dst config receive.certnonceseed sekrit &&
      	git -C dst config receive.advertisepushoptions 1 &&
    @@ t/t6011-rev-list-with-bad-commit.sh: test_expect_success 'verify number of revis
     +test_expect_success 'corrupt second commit object' '
     +	for p in .git/objects/pack/*.pack
     +	do
    -+		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
    ++		sed "s/second commit/socond commit/" "$p" >"$p.munged" &&
     +		mv "$p.munged" "$p" ||
     +		return 1
     +	done &&
    @@ t/t7416-submodule-dash-url.sh: test_expect_success 'fsck accepts protected dash'
      
      test_expect_success 'remove ./ protection from .gitmodules url' '
     -	perl -i -pe "s{\./}{}" .gitmodules &&
    -+	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
    ++	sed "s|\./||" .gitmodules >.gitmodules.munged &&
     +	mv .gitmodules.munged .gitmodules &&
      	git commit -am "drop protection"
      '
    @@ t/t8006-blame-textconv.sh: find_blame() {
      #!/bin/sh
      grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
     -"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
    -+sed 's/^bin: /converted: /' <"$1"
    ++sed 's/^bin: /converted: /' "$1"
      EOF
      chmod +x helper
      
    @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'initialize repo'
      	(cd tmp &&
     -		perl -i.bak -p -e "s/^58$/5588/" file &&
     -		perl -i.bak -p -e "s/^61$/6611/" file &&
    -+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
    ++		sed -e "s/^58$/5588/" -e "s/^61$/6611/" file >file.munged &&
     +		mv file.munged file &&
      		poke file &&
      		test x"$(sed -n -e 58p < file)" = x5588 &&
    @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'some unrelated c
     -	perl -i.bak -p -e 's/^7\$/7777/' file &&
     +	sed -e 's/^4\$/4444/' \
     +	    -e 's/^7\$/7777/' \
    -+		<file >file.munged &&
    ++		file >file.munged &&
     +	mv file.munged file &&
      	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
      	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
12:  e978d8ecfde ! 12:  17f862eaba3 t: refactor tests depending on Perl to print data
    @@ t/t5300-pack-object.sh: test_expect_success 'pack-object <stdin parsing: --stdin
      # e.g.: check_deltas stderr -gt 0
      check_deltas() {
     -	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
    -+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' <"$1") &&
    ++	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' "$1") &&
      	shift &&
      	if ! test "$deltas" "$@"
      	then
    @@ t/t5326-multi-pack-bitmaps.sh: test_midx_bitmap_cases () {
      
     -			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
     -				<before | git update-ref --stdin &&
    -+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
    ++			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
     +			git update-ref --stdin &&
      
      			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
    @@ t/t5333-pseudo-merge-bitmaps.sh: test_pseudo_merges_reused () {
     -	perl -lne '
     -		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
     -	' <in | git update-ref --stdin
    -+	sed 's|\(.*\)|create refs/tags/\1 \1|' <in |
    ++	sed 's|\(.*\)|create refs/tags/\1 \1|' in |
     +	git update-ref --stdin
      }
      
    @@ t/t5333-pseudo-merge-bitmaps.sh: test_expect_success 'pseudo-merge pattern with
      			git rev-list HEAD~16.. >in &&
     -
     -			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
    -+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" <in |
    ++			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" in |
      			git update-ref --stdin || return 1
      		done &&
      
    @@ t/t8002-blame.sh: test_expect_success 'set up abbrev tests' '
      		echo $sha1 | cut -c 1-$expect >expect &&
      		git blame "$@" abbrev.t >actual &&
     -		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
    -+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" <actual >actual.sha &&
    ++		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" actual >actual.sha &&
      		test_cmp expect actual.sha
      	}
      '
13:  905c25c9fb2 = 13:  7b03d096ccd t: refactor tests depending on Perl for textconv scripts
14:  1fe67bba30f = 14:  195c0bf2445 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
15:  9e572c3ba67 = 15:  e92d178b96b t/lib-t6000: refactor `name_from_description()` to not depend on Perl
16:  24abcffe96e ! 16:  0f2c9ad276b t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
    @@ t/t5537-fetch-shallow.sh: test_expect_success PERL_TEST_HELPERS 'shallow fetches
     -	       "$(git -C "$REPO" rev-parse HEAD^)" \
     -	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
    -+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" <"\$1"
    ++	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" "\$1"
     +	EOF
      	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
     -		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
    @@ t/t5616-partial-clone.sh: intersperse () {
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
     +	if grep packfile "\$1" >/dev/null
     +	then
    -+		sed '/packfile/q' <"\$1" &&
    ++		sed '/packfile/q' "\$1" &&
     +		# The protocol requires that the packfile be sent in sideband
     +		# 1, hence the extra \001 byte at the beginning.
     +		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
    @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server sends
     -	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
     -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
    -+	sed "/ready/{n;s/0001/0000/;}" <"$1"
    ++	sed "/ready/{n;s/0001/0000/;}" "$1"
     +	EOF
      
      	test_must_fail git -C http_child -c protocol.version=2 \
    @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server does
     -	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
     -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
    -+	sed "/acknowledgments/,//{s/0000/0001/;}" <"$1"
    ++	sed "/acknowledgments/,//{s/0000/0001/;}" "$1"
     +	EOF
      
      	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
    @@ t/t5702-protocol-v2.sh: test_expect_success 'http:// --negotiate-only' '
     -	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
     -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
    -+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" <"$1"
    ++	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" "$1"
     +	EOF
      
      	test_must_fail git -c protocol.version=2 -C client fetch \
    @@ t/t5703-upload-pack-ref-in-want.sh: inconsistency () {
      	oid2=$(git -C "$REPO" rev-parse $2) &&
     -	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
    -+	sed "s/$oid1/$oid2/" <"\$1"
    ++	sed "s/$oid1/$oid2/" "\$1"
     +	EOF
      }
      
    @@ t/t5703-upload-pack-ref-in-want.sh: test_expect_success 'server loses a ref - re
      	cp -r "$LOCAL_PRISTINE" local &&
     -	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
     +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
    -+	sed "s/main/rain/" <"$1"
    ++	sed "s/main/rain/" "$1"
     +	EOF
      	test_must_fail git -C local fetch 2>err &&
      
17:  ce5adbd4818 = 17:  9857b461ed6 t0021: refactor `generate_random_characters()` to not depend on Perl
18:  e183c397da9 = 18:  7924b5bd9bf t0210: refactor trace2 scrubbing to not use Perl
19:  156bdc4d62d = 19:  5d6996a1412 t5316: refactor `max_chain()` to not depend on Perl
20:  3b181d0a203 = 20:  0c3afb70128 t5703: refactor test to not depend on Perl

---
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
change-id: 20250317-b4-pks-t-perlless-138cf94696b8


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
@ 2025-03-27 10:36   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
                     ` (20 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:36 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our chainlint script verifies that test files have proper '&&' chains.
This script is written in Perl and executed for every test file before
executing the test logic itself.

In subsequent commits we're about to refactor our test suite so that
Perl becomes an optional dependency, only. And while it is already
possible to disable this linter, developers that don't have Perl
available at all would always have to disable the linter manually, which
is rather cumbersome.

Disable the chain linter automatically in case PERL_PATH isn't set to
make this a bit less annoying. Bail out with an error in case the
developer has asked explicitly for the chain linter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9001ed3a647..1ce3b32fcac 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1523,6 +1523,22 @@ then
 	export LSAN_OPTIONS
 fi
 
+if test -z "$PERL_PATH"
+then
+	case "${GIT_TEST_CHAIN_LINT:-unset}" in
+	unset)
+		GIT_TEST_CHAIN_LINT=0
+		;;
+	0)
+		# The user has explicitly disabled the chain linter, so we
+		# don't have anything to worry about.
+		;;
+	*)
+		BAIL_OUT 'You need Perl for the chain linter'
+		;;
+	esac
+fi
+
 if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
    test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 02/20] t: refactor environment sanitization to not use Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-27 10:36   ` [PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 03/20] t: adapt character translation helpers " Patrick Steinhardt
                     ` (19 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Before executing tests we first sanitize the environment. Part of the
sanitization is to unset a couple of environment variables that we know
will change the behaviour of Git. This is done with a small Perl script,
which has the consequence that having a Perl interpreter available is a
strict requirement for running our unit tests.

The logic itself isn't particularly involved: we simply unset every
environment variable whose key starts with 'GIT_', but then explicitly
allow a subset of these.

Refactor the logic to instead use sed(1) so that it becomes possible to
execute our tests without Perl.

Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1ce3b32fcac..a62699d6c79 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -499,24 +499,20 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
-	my @env = keys %ENV;
-	my $ok = join("|", qw(
-		TRACE
-		DEBUG
-		TEST
-		.*_TEST
-		PROVE
-		VALGRIND
-		UNZIP
-		PERF_
-		CURL_VERBOSE
-		TRACE_CURL
-		BUILD_DIR
-	));
-	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
-	print join("\n", @vars);
-')
+unset VISUAL EMAIL LANGUAGE $(env | sed -n \
+	-e '/^GIT_TRACE/d' \
+	-e '/^GIT_DEBUG/d' \
+	-e '/^GIT_TEST/d' \
+	-e '/^GIT_.*_TEST/d' \
+	-e '/^GIT_PROVE/d' \
+	-e '/^GIT_VALGRIND/d' \
+	-e '/^GIT_UNZIP/d' \
+	-e '/^GIT_PERF_/d' \
+	-e '/^GIT_CURL_VERBOSE/d' \
+	-e '/^GIT_TRACE_CURL/d' \
+	-e '/^GIT_BUILD_DIR/d' \
+	-e 's/^\(GIT_[^=]*\)=.*/\1/p'
+)
 unset XDG_CACHE_HOME
 unset XDG_CONFIG_HOME
 unset GITPERLLIB

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 03/20] t: adapt character translation helpers to not use Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
  2025-03-27 10:36   ` [PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
                     ` (18 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of helper functions that translate characters, e.g.
from LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl
scripts, but they can be trivially adapted to instead use tr(1).

Note that one specialty here is the handling of NUL characters in tr(1),
which historically wasn't implemented correctly on all platforms. But
quoting tr(1p):

    It was considered that automatically stripping NUL characters from
    the input was not correct functionality.  However, the removal of -n
    in a later proposal does not remove the requirement that tr
    correctly process NUL characters in its input stream.

So when tr(1) is implemented following the POSIX standard then it is
expected to handle the transliteration of NUL just fine.

Refactor the helpers accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 79377bc0fc2..377f08a1428 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -88,15 +88,15 @@ test_decode_color () {
 }
 
 lf_to_nul () {
-	perl -pe 'y/\012/\000/'
+	tr '\012' '\000'
 }
 
 nul_to_q () {
-	perl -pe 'y/\000/Q/'
+	tr '\000' 'Q'
 }
 
 q_to_nul () {
-	perl -pe 'y/Q/\000/'
+	tr 'Q' '\000'
 }
 
 q_to_cr () {

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 04/20] t: adapt `test_copy_bytes()` to not use Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 03/20] t: adapt character translation helpers " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
                     ` (17 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_copy_bytes()` helper function copies up to N bytes from stdin
to stdout. This is implemented using Perl, but it can be trivially
adapted to instead use dd(1).

Refactor the helper accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 377f08a1428..c4b4d3a4c7f 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1640,17 +1640,7 @@ test_match_signal () {
 
 # Read up to "$1" bytes (or to EOF) from stdin and write them to stdout.
 test_copy_bytes () {
-	perl -e '
-		my $len = $ARGV[1];
-		while ($len > 0) {
-			my $s;
-			my $nread = sysread(STDIN, $s, $len);
-			die "cannot read: $!" unless defined($nread);
-			last unless $nread;
-			print $s;
-			$len -= $nread;
-		}
-	' - "$1"
+	dd ibs=1 count="$1" 2>/dev/null
 }
 
 # run "$@" inside a non-git directory

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 05/20] t: adapt `test_readlink()` to not use Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (3 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
                     ` (16 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_readlink()` helper function reads a symbolic link and returns
the path it is pointing to. It is thus equivalent to the readlink(1)
utility, which isn't available on all supported platforms. As such, it
is implemented using Perl so that we can use it even on platforms where
the shell utility isn't available.

While using readlink(1) is not an option, what we can do is to implement
the logic ourselves in our test-tool. Do so, which allows a bunch of
tests to pass when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-path-utils.c | 13 +++++++++++++
 t/test-lib-functions.sh    |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 72ac8d1b1b0..54d9ba98c0e 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)
 		return 0;
 	}
 
+	if (argc >= 2 && !strcmp(argv[1], "readlink")) {
+		struct strbuf target = STRBUF_INIT;
+		while (argc > 2) {
+			if (strbuf_readlink(&target, argv[2], 0) < 0)
+				die_errno("cannot read link at '%s'", argv[2]);
+			puts(target.buf);
+			argc--;
+			argv++;
+		}
+		strbuf_release(&target);
+		return 0;
+	}
+
 	if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
 		while (argc > 2) {
 			puts(absolute_path(argv[2]));
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c4b4d3a4c7f..bff8c4d1b41 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1979,7 +1979,7 @@ test_remote_https_urls() {
 # Print the destination of symlink(s) provided as arguments. Basically
 # the same as the readlink command, but it's not available everywhere.
 test_readlink () {
-	perl -le 'print readlink($_) for @ARGV' "$@"
+	test-tool path-utils readlink "$@"
 }
 
 # Set mtime to a fixed "magic" timestamp in mid February 2009, before we

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (4 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 18:26     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
                     ` (15 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

In the early days of Git, Perl was used quite prominently throughout the
project. This has changed significantly as almost all of the executables
we ship nowadays have eventually been rewritten in C. Only a handful of
subsystems remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these subsystems can really be considered to be part of the
"core" of Git, and an installation without them is fully functional.
It is more likely than not that an end user wouldn't even notice that
any features are missing if those tools weren't installed. But while
Perl nowadays very much is an optional dependency of Git, there is a
significant limitation when Perl isn't available: developers cannot run
our test suite.

Preceding commits have started to lift this restriction by removing the
strict dependency on Perl in many central parts of the test library. But
there are still many tests that rely on small Perl helpers to do various
different things.

Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
that require Perl. This prerequisite is explicitly different than the
preexisting PERL prerequisite:

  - PERL records whether or not features depending on the Perl
    interpreter are built.

  - PERL_TEST_HELPERS records whether or not a Perl interpreter is
    available for our tests.

By having these two separate prerequisites we can thus distinguish
between tests that inherently depend on Perl because the underlying
feature does, and those tests that depend on Perl because the test
itself is using Perl.

Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        |  6 ++++++
 t/t0021-conversion.sh                     |  4 ++--
 t/t0210-trace2-normal.sh                  |  6 ++++++
 t/t0211-trace2-perf.sh                    |  6 ++++++
 t/t0610-reftable-basics.sh                |  2 +-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       |  2 +-
 t/t1007-hash-object.sh                    |  6 +++---
 t/t1010-mktree.sh                         |  4 ++--
 t/t1450-fsck.sh                           |  6 +++---
 t/t3300-funny-names.sh                    |  6 +++---
 t/t4013-diff-various.sh                   |  6 ++++++
 t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------
 t/t4020-diff-external.sh                  |  4 ++--
 t/t4029-diff-trailing-space.sh            |  2 +-
 t/t4030-diff-textconv.sh                  |  6 ++++++
 t/t4031-diff-rewrite-binary.sh            |  2 +-
 t/t4058-diff-duplicates.sh                |  6 ++++++
 t/t4103-apply-binary.sh                   |  6 ++++++
 t/t4116-apply-reverse.sh                  |  6 ++++++
 t/t4150-am.sh                             |  2 +-
 t/t4200-rerere.sh                         |  6 ++++++
 t/t4205-log-pretty-formats.sh             |  6 +++---
 t/t4216-log-bloom.sh                      |  8 ++++----
 t/t5004-archive-corner-cases.sh           |  6 ++++++
 t/t5300-pack-object.sh                    |  6 ++++++
 t/t5303-pack-corruption-resilience.sh     |  4 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               |  8 ++++----
 t/t5318-commit-graph.sh                   | 12 ++++++------
 t/t5319-multi-pack-index.sh               | 16 ++++++++--------
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  2 +-
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  4 ++--
 t/t5503-tagfollow.sh                      |  6 ++++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++++
 t/t5532-fetch-proxy.sh                    |  6 ++++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  |  2 +-
 t/t5551-http-fetch-smart.sh               |  7 +++++++
 t/t5562-http-backend-content-length.sh    |  6 ++++++
 t/t5601-clone.sh                          |  4 ++--
 t/t5616-partial-clone.sh                  |  6 +++---
 t/t5701-git-serve.sh                      |  2 +-
 t/t5702-protocol-v2.sh                    |  6 +++---
 t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++
 t/t5710-promisor-remote-capability.sh     |  6 ++++++
 t/t6002-rev-list-bisect.sh                |  6 ++++++
 t/t6003-rev-list-topo-order.sh            |  6 ++++++
 t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++
 t/t6013-rev-list-reverse-parents.sh       |  4 ++--
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++
 t/t6115-rev-list-du.sh                    |  6 ++++++
 t/t6300-for-each-ref.sh                   |  6 ++++++
 t/t7006-pager.sh                          |  2 +-
 t/t7416-submodule-dash-url.sh             |  6 ++++++
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  6 ++++++
 t/t8001-annotate.sh                       |  6 ++++++
 t/t8002-blame.sh                          |  6 ++++++
 t/t8006-blame-textconv.sh                 |  6 ++++++
 t/t8011-blame-split-file.sh               |  6 +++---
 t/t8012-blame-colors.sh                   |  6 ++++++
 t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib.sh                             |  1 +
 71 files changed, 281 insertions(+), 93 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index c9376dffb58..1aaa6bf5ae8 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,6 +5,12 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping ignores tests; Perl not available'
+	test_done
+fi
+
 init_vars () {
 	global_excludes="global-excludes"
 }
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 3f6433d3045..9c3738ebb3f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success 'required process filter should process multiple packets' '
+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '
 	)
 '
 
-test_expect_success 'required process filter with clean error should fail' '
+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index 4287ed3fbb3..ba4c0442b85 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index bac90465406..760cf69087f 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_PERF_BRIEF
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 4618ffc108e..5e0a1fa176d 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success 'basic: can write large commit message' '
+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	perl -e "
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index e2708e11d5b..fa1e2f9eef8 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success 'small block size fails with large reflog message' '
+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 398865d6ebe..a574da3df53 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1270,7 +1270,7 @@ extract_batch_output () {
     ' "$@"
 }
 
-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '
 	git cat-file --batch-all-objects --batch >actual.raw &&
 	extract_batch_output $orig <actual.raw >actual &&
 	{
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index a0481139de5..b3cf53ff8c9 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '
 	grep "too-short tree object" err
 '
 
-test_expect_success 'malformed mode in tree' '
+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "9100644 \0$bin_oid" >tree-with-malformed-mode &&
@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '
 	grep "malformed mode in tree entry" err
 '
 
-test_expect_success 'empty filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "100644 \0$bin_oid" >tree-with-empty-filename &&
@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '
 	grep "empty filename in tree entry" err
 '
 
-test_expect_success 'duplicate filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	{
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index c291a2b33d7..4977998e205 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
 	perl -e "print reverse <>" <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
 	perl -e "print reverse <>" <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1142d..01050453762 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '
 	test_grep ! "fatal: empty filename in tree entry" out
 '
 
-test_expect_success 'tree entry with type mismatch' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	test_when_finished "remove_object \$commit" &&
@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '
 	test_grep ! "dangling blob" out
 '
 
-test_expect_success 'tree entry with bogus mode' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	blob=$(echo blob | git hash-object -w --stdin) &&
@@ -984,7 +984,7 @@ corrupt_index_checksum () {
 
 # Corrupt the checksum on the index and then
 # verify that only fsck notices.
-test_expect_success 'detect corrupt index file in fsck' '
+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '
 	cp .git/index .git/index.backup &&
 	test_when_finished "mv .git/index.backup .git/index" &&
 	corrupt_index_checksum &&
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index f5bf16abcd8..502b1572059 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'ls-files -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-index -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-tree -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68dbc0..782d97fb7df 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff various tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83fb8a4..2782b1fc183 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF
 ---
 EOF
 
-test_expect_success 'no threading' '
+test_expect_success PERL_TEST_HELPERS 'no threading' '
 	git checkout side &&
 	check_threading expect.no-threading main
 '
@@ -466,11 +466,11 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread' '
+test_expect_success PERL_TEST_HELPERS 'thread' '
 	check_threading expect.thread --thread main
 '
 
-test_expect_success '--thread overrides format.thread=deep' '
+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
@@ -490,7 +490,7 @@ In-Reply-To: <1>
 References: <1>
 EOF
 
-test_expect_success 'thread in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '
 	check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 		--thread main
 '
@@ -512,7 +512,7 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '
 	check_threading expect.cover-letter --cover-letter --thread main
 '
 
@@ -538,12 +538,12 @@ References: <1>
 	<0>
 EOF
 
-test_expect_success 'thread cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread main
 '
 
-test_expect_success 'thread explicit shallow' '
+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=shallow main
 '
@@ -562,7 +562,7 @@ References: <0>
 	<1>
 EOF
 
-test_expect_success 'thread deep' '
+test_expect_success PERL_TEST_HELPERS 'thread deep' '
 	check_threading expect.deep --thread=deep main
 '
 
@@ -584,7 +584,7 @@ References: <1>
 	<2>
 EOF
 
-test_expect_success 'thread deep in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '
 	check_threading expect.deep-irt  --thread=deep \
 		--in-reply-to="<test.message>" main
 '
@@ -609,7 +609,7 @@ References: <0>
 	<2>
 EOF
 
-test_expect_success 'thread deep cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '
 	check_threading expect.deep-cl --cover-letter --thread=deep main
 '
 
@@ -638,27 +638,27 @@ References: <1>
 	<3>
 EOF
 
-test_expect_success 'thread deep cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '
 	check_threading expect.deep-cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=deep main
 '
 
-test_expect_success 'thread via config' '
+test_expect_success PERL_TEST_HELPERS 'thread via config' '
 	test_config format.thread true &&
 	check_threading expect.thread main
 '
 
-test_expect_success 'thread deep via config' '
+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '
 	test_config format.thread deep &&
 	check_threading expect.deep main
 '
 
-test_expect_success 'thread config + override' '
+test_expect_success PERL_TEST_HELPERS 'thread config + override' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
 
-test_expect_success 'thread config + --no-thread' '
+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '
 	test_config format.thread deep &&
 	check_threading expect.no-threading --no-thread main
 '
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index f1efe482a59..189294de7ef 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet
 
 echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
 
-test_expect_success 'force diff with "diff"' '
+test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success 'diff --cached' '
+test_expect_success PERL_TEST_HELPERS 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index 32b6e9a4e76..a92a42990b1 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success "$test_description" '
+test_expect_success PERL_TEST_HELPERS "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index daebf9796f5..c7d8eb12453 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff textconv tests; Perl not available'
+	test_done
+fi
+
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index c4394a27b56..cbe50b15772 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success 'rewrite diff respects textconv' '
+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
 	git diff -B >diff &&
 	grep "dissimilarity index" diff &&
 	grep "^-61" diff &&
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2fce4a98977..16266dff2af 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff duplicates tests; Perl not available'
+	test_done
+fi
+
 # make_tree_entry <mode> <mode> <sha1>
 #
 # We have to rely on perl here because not all printfs understand
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index d370ecfe0d9..59d38793ae6 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply-binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 0784ba033a4..6f414ad27f5 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,6 +10,12 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply reverse tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c80eae..4794510d70d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success 'am works with multi-line in-body headers' '
+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b0a3e849841..50fe8b0fd05 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rerere tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f81e42a84d5..8f2ba98963f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trail
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:unfold) unfolds trailers' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '
 	git log --no-walk --pretty="%(trailers:unfold)" >actual &&
 	{
 		unfold <trailers &&
@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '
 	test_cmp expect actual
 '
 
-test_expect_success ':only and :unfold work together' '
+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '
 	git log --no-walk --pretty="%(trailers:only,unfold)" >actual &&
 	git log --no-walk --pretty="%(trailers:unfold,only)" >reverse &&
 	test_cmp actual reverse &&
@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '
 	git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual &&
 	unfold <trailers | grep Signed-off-by >expect &&
 	test_cmp expect actual
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 3f163dc3969..8910d53cac1 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -738,20 +738,20 @@ check_corrupt_graph () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'Bloom reader notices too-small data chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
 	check_corrupt_graph BDAT clear 00000000 &&
 	echo "warning: ignoring too-small changed-path chunk" \
 		"(4 < 12) in commit-graph file" >expect.err &&
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
 	check_corrupt_graph BIDX 12 FFFFFFFF &&
 	# use grep to avoid depending on exact chunk size
 	grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
 '
 
-test_expect_success 'Bloom reader notices too-small index chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
 	# replace the index with a single entry, making most
 	# lookups out-of-bounds
 	check_corrupt_graph BIDX clear 00000000 &&
@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-order index offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
 	# we do not know any real offsets, but we can pick
 	# something plausible; we should not get to the point of
 	# actually reading from the bogus offsets anyway.
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 50344e17ca1..51749951916 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping archive corner cases tests; Perl not available'
+	test_done
+fi
+
 # the 10knuls.tar file is used to test for an empty git generated tar
 # without having to invoke tar because an otherwise valid empty GNU tar
 # will be considered broken by {Open,Net}BSD tar
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 5ac8d39094b..143856c29f1 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,6 +7,12 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pack-object tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	rm -f .git/index* &&
 	perl -e "print \"a\" x 4096;" >a &&
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index de58ca654a1..ac5e370e1e4 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first object' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
@@ -156,7 +156,7 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first delta' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 621bbbdd26e..81987296235 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 32cf4227451..cd947b5a5ef 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -87,7 +87,7 @@ max_chain() {
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success 'packing produces a long delta' '
+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success '--depth limits depth' '
+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success '--depth=0 disables deltas' '
+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success 'negative depth disables deltas' '
+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index f68f64cd85e..0b3404f58fe 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -837,7 +837,7 @@ check_corrupt_chunk () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	# make it big enough that the graph file is plausible,
 	# otherwise we hit an earlier check
 	check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices fanout/lookup table mismatch' '
+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '
 	check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph OID lookup chunk is the wrong size
@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# Rather than try to corrupt a specific hash, we will just
 	# wreck them all. But we cannot just set them all to 0xFFFFFFFF or
 	# similar, as they are used for hi/lo starts in a binary search (so if
@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small commit data chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '
 	check_corrupt_chunk CDAT clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph commit data chunk is wrong size
@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds extra edge' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '
 	check_corrupt_chunk EDGE clear &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph extra-edges pointer out of bounds
@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small generations chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '
 	check_corrupt_chunk GDA2 clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph generations chunk is wrong size
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 0f215ad2e88..bd75dea9501 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1120,7 +1120,7 @@ corrupt_chunk () {
 	corrupt_chunk_file $midx "$@"
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	corrupt_chunk OIDF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small oid lookup chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '
 	corrupt_chunk OIDL clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small pack names chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '
 	# There is no NUL to terminate the name here, so the
 	# chunk is too short.
 	corrupt_chunk PNAM clear 70656666 &&
@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader handles unaligned chunks' '
+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '
 	# A 9-byte PNAM means all of the subsequent chunks
 	# will no longer be 4-byte aligned, but it is still
 	# a valid one-pack chunk on its own (it is "foo.pack\0").
@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small object offset chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '
 	corrupt_chunk OOFF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader bounds-checks large offset table' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '
 	# re-use the objects64 dir here to cheaply get access to a midx
 	# with large offsets.
 	git init repo &&
@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '
 	)
 '
 
-test_expect_success 'reader notices too-small revindex chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '
 	# We only get a revindex with bitmaps (and likewise only
 	# load it when they are asked for).
 	test_config repack.writeBitmaps true &&
@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# This is similar to the out-of-bounds fanout test in t5318. The values
 	# in adjacent entries should be large but not identical (they
 	# are used as hi/lo starts for a binary search, which would then abort
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index a32be3867df..49a057cc2eb 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '
 	)
 '
 
-test_expect_success 'reader bounds-checks base-graph chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '
 	git clone --no-hardlinks . corrupt-base-chunk &&
 	(
 		cd corrupt-base-chunk &&
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index d27557b9b04..627f8b4efdc 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index a766a3e3f84..d8891e6a922 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
 	git -C repo-uint32-max commit-graph verify
 '
 
-test_expect_success 'reader notices out-of-bounds generation overflow' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '
 	graph=.git/objects/info/commit-graph &&
 	test_when_finished "rm -rf $graph" &&
 	git commit-graph write --reachable &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 3905cb6e4f1..1059ff45fe4 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
+	test_done
+fi
+
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16e133..571e8f1bc59 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -268,7 +268,7 @@ extract_ref_advertisement () {
 	'
 }
 
-test_expect_success 'receive-pack de-dupes .have lines' '
+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '
 	git init shared &&
 	git -C shared commit --allow-empty -m both &&
 	git clone -s shared fork &&
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 0b28e4e452f..6a009fdcd71 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -20,7 +20,7 @@ extract_haves () {
 	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
 }
 
-test_expect_success 'with core.alternateRefsCommand' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success 'with core.alternateRefsPrefixes' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 845ca43ea0a..febe4410417 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping tagfollow tests; Perl not available'
+	test_done
+fi
+
 # End state of the repository:
 #
 #         T - tag1          S - tag2
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 58074506c59..438250c75ed 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -359,7 +359,7 @@ test_expect_success \
 	grep "Cannot demote unterminatedheader" act
 '
 
-test_expect_success 'badFilemode is not a strict error' '
+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '
 	git init --bare badmode.git &&
 	tree=$(
 		cd badmode.git &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 5f350facf5e..432a2264e6f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -8,6 +8,12 @@ test_description='Per branch config variables affects "git fetch".
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch tests; Perl not available'
+	test_done
+fi
+
 D=$(pwd)
 
 test_expect_success setup '
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
index 37558226290..95d0f33b295 100755
--- a/t/t5532-fetch-proxy.sh
+++ b/t/t5532-fetch-proxy.sh
@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch proxy tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup remote repo' '
 	git init remote &&
 	(cd remote &&
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index c91a62b77af..342d0423c92 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 37f7547a4ca..77d20d19110 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 761fdfcfe6c..b0d4ea78015 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
+
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http fetch smart tests; Perl not available'
+	test_done
+fi
+
 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
 start_httpd
 
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index f3b158274c4..b6ee06f5c8f 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http backend content tests; Perl not available'
+	test_done
+fi
+
 test_lazy_prereq GZIP 'gzip --version'
 
 verify_http_result() {
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d0c18660e33..d743d986c40 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
 	git -C replay.git index-pack -v --stdin <tmp.pack
 '
 
-test_expect_success 'clone on case-insensitive fs' '
+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '
 	git init icasefs &&
 	(
 		cd icasefs &&
@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '
 	)
 '
 
-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '
 	grep X icasefs/warning &&
 	grep x icasefs/warning &&
 	test_grep "the following paths have collided" icasefs/warning
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 46504519643..bc7e0fec8dc 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -751,7 +751,7 @@ replace_packfile () {
 	}' >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
-test_expect_success 'upon cloning, check that all refs point to objects' '
+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 678a346ed06..200bf06ecb3 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success 'ignore very large set of prefixes' '
+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index d3df81e7852..ad5e772cd72 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success 'when server sends "ready", expect DELIM' '
+test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends "ready", expect DELIM' '
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success 'when server does not send "ready", expect FLUSH' '
+test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
 	URI="$HTTPD_URL/one_time_perl/server" &&
 
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 191097171bc..f59d47aa6c6 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
+	test_done
+fi
+
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index d2cc69a17e4..9a420cf5605 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping promisor remote capabilities tests; Perl not available'
+	test_done
+fi
+
 GIT_TEST_MULTI_PACK_INDEX=0
 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index daa009c9a1b..5e1482aff78 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list bisect tests; Perl not available'
+	test_done
+fi
+
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 0d7055d46d4..02dd4127aff 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list topo-order tests; Perl not available'
+	test_done
+fi
+
 list_duplicates()
 {
     "$@" | sort | uniq -d
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index bad02cf5b83..6131c361094 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list with bad commit tests; Perl not available'
+	test_done
+fi
+
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 39793cbbd66..8074185742c 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success '--reverse --parents --full-history combines correctly' '
+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
 	git rev-list --parents --full-history main -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '
 	test_cmp expected actual
 	'
 
-test_expect_success '--boundary does too' '
+test_expect_success PERL_TEST_HELPERS '--boundary does too' '
 	git rev-list --boundary --parents --full-history main ^root -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --boundary --reverse --parents --full-history \
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 22dfd6d978e..eb98b3919c8 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list unexpected objects tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup well-formed objects' '
 	blob="$(printf "foo" | git hash-object -w --stdin)" &&
 	tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 3385fe9f130..6a74be576a2 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list disk usage tests; Perl not available'
+	test_done
+fi
+
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a5c77943854..732a4d3171e 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping for-each-ref tests; Perl not available'
+	test_done
+fi
+
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 932c26cb45b..49aae183829 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success 'setup large log output' '
+test_expect_success PERL_TEST_HELPERS 'setup large log output' '
 	perl -e "
 		print \"this is a long commit message\" x 50000
 	" >commit-msg &&
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 0c605fd271a..14069600a2f 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping submodule dash URL tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index b2070d4e39f..14c41b2cb7c 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success 'status -z implies porcelain' '
+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
 	git status --porcelain |
 	perl -pe "s/\012/\000/g" >expect &&
 	git status -z >output &&
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index 90ebb64f46e..b2730d200c8 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,6 +4,12 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping grep binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index d7167f55397..609845aeb1e 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping annotate tests; Perl not available'
+	test_done
+fi
+
 PROG='git annotate'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index e98993276a6..b40199df231 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 07a287ffd3e..5cb16872081 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,6 +4,12 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame textconv tests; Perl not available'
+	test_done
+fi
+
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh
index c66494f5ba7..388057245c8 100755
--- a/t/t8011-blame-split-file.sh
+++ b/t/t8011-blame-split-file.sh
@@ -81,7 +81,7 @@ do
 		git blame --root -C --$output combined >output
 	'
 
-	test_expect_success "$output output finds correct commits" '
+	test_expect_success PERL_TEST_HELPERS "$output output finds correct commits" '
 		generate_expect >expect <<-\EOF &&
 		5 base
 		1 modified
@@ -93,7 +93,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct filenames" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct filenames" '
 		generate_expect >expect <<-\EOF &&
 		11 one
 		11 two
@@ -102,7 +102,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct previous pointer" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct previous pointer" '
 		generate_expect >expect <<-EOF &&
 		5 NONE
 		1 $(git rev-parse modified^) one
diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh
index c3a5f6d01ff..3d77352650f 100755
--- a/t/t8012-blame-colors.sh
+++ b/t/t8012-blame-colors.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index 067b15bad25..a9d38be997c 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' '
+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success 'change file but in unrelated area' "
+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
 	perl -i.bak -p -e 's/^4\$/4444/' file &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 40427883ec6..0781a8d6ace 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '
 	(cd result && git show main:foo)
 '
 
-test_expect_success 'fast-export quotes pathnames' '
+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '
 	git init crazy-paths &&
 	test_config -C crazy-paths core.protectNTFS false &&
 	(cd crazy-paths &&
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index 36566ace21b..f619b60f226 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success 'shell complains of overlong commands' '
+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
 	perl -e "print \"a\" x 2**12 for (0..2**19)" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a62699d6c79..59162a3c834 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1706,6 +1706,7 @@ test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
 test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
 test -n "$GIT_VALGRIND_ENABLED" && test_set_prereq VALGRIND
+test -n "$PERL_PATH" && test_set_prereq PERL_TEST_HELPERS
 
 if test -z "$GIT_TEST_CHECK_CACHE_TREE"
 then

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 07/20] t: adapt existing PERL prerequisites
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (5 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
                     ` (14 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A couple of our tests depend on the PERL prerequisite even though it
isn't needed. These tests fall into one of the following classes:

  - The underlying logic used to be implemented in Perl but isn't
    anymore. Here we can simply drop the dependency altogether.

  - The test logic used to depend on Perl but doesn't anymore. Again, we
    can simply drop the dependency.

  - The test logic still relies on a Perl interpreter. These tests
    should use the newly introduced PERL_TEST_HELPERS prerequisite.

Adapt test cases accordingly.

Note that in t1006 we have to introduce another new prerequisite
depending on whether or not the IPC::Open2 module is available. Funny
enough, when starting to use `test_lazy_prereq` to do so we also get a
conflict of variables with the "script" variable that contains the Perl
logic because `test_run_lazy_prereq_` also sets that variable. We thus
rename the variable in t1006 to "perl_script".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh                 | 10 +++++-----
 t/t0090-cache-tree.sh                 |  4 ++--
 t/t1006-cat-file.sh                   | 14 +++++++++-----
 t/t7501-commit-basic-functionality.sh |  6 +++---
 4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9c3738ebb3f..4a892a91780 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'
 	)
 '
 
-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
+test_expect_success 'invalid process filter must fail (and not hang!)' '
 	test_config_global filter.protocol.process cat &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
@@ -1111,19 +1111,19 @@ do
 	branch) opt='-f HEAD' ;;
 	esac
 
-	test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
+	test_expect_success TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
 		test_delayed_checkout_progress test_terminal git checkout $opt
 	'
 
-	test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" '
+	test_expect_success "delayed checkout omits progress on non-tty ($mode checkout)" '
 		test_delayed_checkout_progress ! git checkout $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
+	test_expect_success TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
+	test_expect_success TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&
 		test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt
 	'
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index ab80c9ef135..d9015882946 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '
 	test_cache_tree
 '
 
-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
 	test_when_finished "git reset --hard" &&
 	cat <<-\EOT >foo.c &&
 	int foo()
@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
 	test_cache_tree expected.status
 '
 
-test_expect_success PERL 'commit -p with shrinking cache-tree' '
+test_expect_success 'commit -p with shrinking cache-tree' '
 	mkdir -p deep/very-long-subdir &&
 	echo content >deep/very-long-subdir/file &&
 	git add deep &&
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index a574da3df53..0a22b0a7b8e 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '
 	grep "^fatal:.*flush is only for --buffer mode.*" err
 '
 
-script='
+perl_script='
 use warnings;
 use strict;
 use IPC::Open2;
@@ -1345,12 +1345,16 @@ $? == 0 or die "\$?=$?";
 
 expect="$hello_oid blob $hello_size"
 
-test_expect_success PERL '--batch-check is unbuffered by default' '
-	perl -e "$script" -- --batch-check $hello_oid "$expect"
+test_lazy_prereq PERL_IPC_OPEN2 '
+	perl -MIPC::Open2 -e "exit 0"
 '
 
-test_expect_success PERL '--batch-command info is unbuffered by default' '
-	perl -e "$script" -- --batch-command $hello_oid "$expect" "info "
+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-check $hello_oid "$expect"
+'
+
+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-command $hello_oid "$expect" "info "
 '
 
 test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index cc12f99f115..a37509f0043 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '
 	test_must_fail git commit -m foo -a file
 '
 
-test_expect_success PERL 'can use paths with --interactive' '
+test_expect_success 'can use paths with --interactive' '
 	echo bong-o-bong >file &&
 	# 2: update, 1:st path, that is all, 7: quit
 	test_write_lines 2 1 "" 7 |
@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '
 	grep Rubber.Duck output
 '
 
-test_expect_success PERL 'interactive add' '
+test_expect_success 'interactive add' '
 	echo 7 | test_must_fail git commit --interactive >out &&
 	grep "What now" out
 '
 
-test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
+test_expect_success "commit --interactive doesn't change index if editor aborts" '
 	echo zoo >file &&
 	test_must_fail git diff --exit-code >diff1 &&
 	test_write_lines u "*" q |

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 08/20] meson: stop requiring Perl when tests are enabled
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (6 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
                     ` (13 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Perl interpreter used to be a strict dependency for running our test
suite. This requirement is explicit in the Meson build system, where we
require Perl to be present unless tests have been disabled.

With the preceding commits we have loosened this restriction so that it
is now possible to run tests when Perl is unavailable. Loosen the above
requirement accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index efe2871c9db..d6e27b236fa 100644
--- a/meson.build
+++ b/meson.build
@@ -772,7 +772,7 @@ endif
 # features. It is optional if you want to neither execute tests nor use any of
 # these optional features.
 perl_required = get_option('perl')
-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
   perl_required = true
 endif
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 09/20] Makefile: stop requiring Perl when running tests
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (7 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
                     ` (12 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Makefile for our tests has a couple of targets that depend on Perl.
Adapt those targets to only run conditionally in case Perl is available
on the system so that it becomes possible to run the test suite without
Perl.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/Makefile | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/t/Makefile b/t/Makefile
index 2994eb5fa9a..791e0a09789 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT
 
 all:: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean check-chainlint check-meson $(TEST_LINT)
+test: pre-clean check-meson $(TEST_LINT)
 	$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
 
+ifneq ($(PERL_PATH),)
+test: check-chainlint
+prove: check-chainlint
+endif
+
 failed:
 	@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \
 		grep -l '^failed [1-9]' *.counts | \
 		sed -n 's/\.counts$$/.sh/p') && \
 	test -z "$$failed" || $(MAKE) $$failed
 
-prove: pre-clean check-chainlint $(TEST_LINT)
+prove: pre-clean $(TEST_LINT)
 	@echo "*** prove (shell & unit tests) ***"
 	@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
 	$(MAKE) clean-except-prove-cache
@@ -132,8 +137,13 @@ check-meson:
 		fi; \
 	done
 
-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
+test-lint: test-lint-duplicates test-lint-executable \
 	test-lint-filenames
+ifneq ($(PERL_PATH),)
+test-lint: test-lint-shell-syntax
+else
+GIT_TEST_CHAIN_LINT = 0
+endif
 ifneq ($(GIT_TEST_CHAIN_LINT),0)
 test-lint: test-chainlint
 endif

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 10/20] t: refactor tests depending on Perl transliteration operator
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (8 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
                     ` (11 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform character
transliteration via the "y/" or "tr/" operator. These usecases can be
trivially replaced with tr(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-sha1.sh    |  4 ++--
 t/lib-diff.sh            |  4 ++--
 t/t3300-funny-names.sh   | 12 ++++++------
 t/t4020-diff-external.sh |  6 +++---
 t/t4103-apply-binary.sh  | 12 +++---------
 t/t4116-apply-reverse.sh | 10 ++--------
 t/t4200-rerere.sh        |  2 +-
 7 files changed, 19 insertions(+), 31 deletions(-)

diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index bf387d3db14..f03b784ddc2 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -15,7 +15,7 @@ do
 			{
 				test -z "$pfx" || echo "$pfx"
 				dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-				perl -pe 'y/\000/g/'
+				tr "\000" "g"
 			} | ./t/helper/test-tool $sha1 $cnt
 		)
 		if test "$expect" = "$actual"
@@ -61,7 +61,7 @@ do
 		{
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-			perl -pe 'y/\000/g/'
+			tr "\000" "g"
 		} | sha1sum |
 		sed -e 's/ .*//'
 	)
diff --git a/t/lib-diff.sh b/t/lib-diff.sh
index c4606bd4b7f..12b3c8fcc6a 100644
--- a/t/lib-diff.sh
+++ b/t/lib-diff.sh
@@ -21,8 +21,8 @@ compare_diff_raw_z () {
     # Also we do not check SHA1 hash generation in this test, which
     # is a job for t0000-basic.sh
 
-    perl -pe 'y/\000/\012/' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
-    perl -pe 'y/\000/\012/' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
+    tr "\000" "\012" <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
+    tr "\000" "\012" <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 502b1572059..dd0586b0073 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
+test_expect_success 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
 	tabs	," (dq) and spaces
 	EOF
 	git ls-files -z >ls-files.z &&
-	perl -pe "y/\000/\012/" <ls-files.z >current &&
+	tr "\000" "\012" <ls-files.z >current &&
 	test_cmp expected current
 '
 
@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
+test_expect_success 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-index -z --name-status $t0 >diff-index.z &&
-	perl -pe "y/\000/\012/" <diff-index.z >current &&
+	tr "\000" "\012" <diff-index.z >current &&
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
+test_expect_success 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-tree -z --name-status $t0 $t1 >diff-tree.z &&
-	perl -pe y/\\000/\\012/ <diff-tree.z >current &&
+	tr "\000" "\012" <diff-tree.z >current &&
 	test_cmp expected current
 '
 
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 189294de7ef..c8a23d51483 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet
 check_external_diff   1 empty  empty 1 on  --quiet
 check_external_diff 128 empty  error 2 on  --quiet
 
-echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
+echo NULZbetweenZwords | tr "Z" "\000" > file
 
-test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
+test_expect_success 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff --cached' '
+test_expect_success 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index 59d38793ae6..8e302a5a57e 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply-binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
@@ -32,10 +26,10 @@ test_expect_success 'setup' '
 	git commit -m "Initial Version" 2>/dev/null &&
 
 	git checkout -b binary &&
-	perl -pe "y/x/\000/" <file1 >file3 &&
+	tr "x" "\000" <file1 >file3 &&
 	cat file3 >file4 &&
 	git add file2 &&
-	perl -pe "y/\000/v/" <file3 >file1 &&
+	tr "y" "\000" <file3 >file1 &&
 	rm -f file2 &&
 	git update-index --add --remove file1 file2 file3 file4 &&
 	git commit -m "Second Version" &&
@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '
 	test -z "$(git diff --name-status binary -- file3)"
 '
 
-test_expect_success 'reject truncated binary diff' '
+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '
 	do_reset &&
 
 	# this length is calculated to get us very close to
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 6f414ad27f5..1e7beab0016 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,23 +10,17 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply reverse tests; Perl not available'
-	test_done
-fi
-
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
-	perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 &&
+	tr "ijk" "\000\001\002" <file1 >file2 &&
 
 	git add file1 file2 &&
 	git commit -m initial &&
 	git tag initial &&
 
 	test_write_lines a b c g h i J K L m o n p q >file1 &&
-	perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 &&
+	tr "mon" "\000\001\002" <file1 >file2 &&
 
 	git commit -a -m second &&
 	git tag second &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 50fe8b0fd05..7fcca9ddad5 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '
 
 test_expect_success 'rerere clear' '
 	mv $rr/postimage .git/post-saved &&
-	echo "$sha1	a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
+	echo "$sha1	a1" | tr "\012" "\000" >.git/MERGE_RR &&
 	git rerere clear &&
 	! test -d $rr
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (9 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 18:32     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
                     ` (10 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform substitution via the
"s/" operator. These usecases can be trivially replaced with sed(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        | 10 ++--------
 t/t4029-diff-trailing-space.sh            |  5 +++--
 t/t4200-rerere.sh                         | 12 +++---------
 t/t5303-pack-corruption-resilience.sh     | 10 ++++++----
 t/t5310-pack-bitmaps.sh                   |  4 ++--
 t/t5534-push-signed.sh                    |  4 ++--
 t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------
 t/t7416-submodule-dash-url.sh             |  9 ++-------
 t/t7508-status.sh                         |  4 ++--
 t/t8006-blame-textconv.sh                 |  8 +-------
 t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------
 11 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 1aaa6bf5ae8..273d71411fe 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,12 +5,6 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping ignores tests; Perl not available'
-	test_done
-fi
-
 init_vars () {
 	global_excludes="global-excludes"
 }
@@ -45,11 +39,11 @@ test_stderr () {
 }
 
 broken_c_unquote () {
-	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
+	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
 }
 
 broken_c_unquote_verbose () {
-	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
+	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
 }
 
 stderr_contains () {
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index a92a42990b1..90cdde88d8b 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success PERL_TEST_HELPERS "$test_description" '
+test_expect_success "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
 	git config --bool diff.suppressBlankEmpty true &&
 	git diff f > actual &&
 	test_cmp exp actual &&
-	perl -i.bak -p -e "s/^\$/ /" exp &&
+	sed "s/^\$/ /" exp >exp.munged &&
+	mv exp.munged exp &&
 	git config --bool diff.suppressBlankEmpty false &&
 	git diff f > actual &&
 	test_cmp exp actual &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 7fcca9ddad5..204325f4d53 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rerere tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
 	test_might_fail git config --unset rerere.enabled &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep "^=======\$" $rr/preimage &&
 	! test -f $rr/postimage &&
@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
 	git reset --hard &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep ^=======$ $rr/preimage
 '
@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
 	git config rerere.enabled true &&
 	git reset --hard &&
 	test_must_fail git merge first &&
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1
 '
 
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index ac5e370e1e4..ab99c8b6850 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
+test_expect_success 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
+	sed "s/ base /abcdef/" ${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	test_must_fail git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
@@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
+test_expect_success 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
+	sed "s/ delta1 /abcdefgh/" ${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 81987296235..a62b463eaf0 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -421,7 +421,7 @@ test_bitmap_cases () {
 
 			# mark the commits which did not receive bitmaps as preferred,
 			# and generate the bitmap again
-			perl -pe "s{^}{create refs/tags/include/$. }" <before |
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
 				git update-ref --stdin &&
 			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
 
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 342d0423c92..2a782214ee1 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
 	# Tweak the push output to make the push option outside the cert
 	# different, then replay it on a fresh dst, checking that ff is not
 	# deleted.
-	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
+	sed "s/\([^ ]\)bar/\1baz/" push >push.tweak &&
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
 	git -C dst config receive.advertisepushoptions 1 &&
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index 6131c361094..b6f3344dbfb 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list with bad commit tests; Perl not available'
-	test_done
-fi
-
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
    first_commit=$(git rev-parse HEAD~3)
    '
 
-test_expect_success 'corrupt second commit object' \
-   '
-   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
-   test_must_fail git fsck --full
-   '
+test_expect_success 'corrupt second commit object' '
+	for p in .git/objects/pack/*.pack
+	do
+		sed "s/second commit/socond commit/" "$p" >"$p.munged" &&
+		mv "$p.munged" "$p" ||
+		return 1
+	done &&
+	test_must_fail git fsck --full
+'
 
 test_expect_success 'rev-list should fail' '
 	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 14069600a2f..3d944a00e0d 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping submodule dash URL tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
 '
 
 test_expect_success 'remove ./ protection from .gitmodules url' '
-	perl -i -pe "s{\./}{}" .gitmodules &&
+	sed "s|\./||" .gitmodules >.gitmodules.munged &&
+	mv .gitmodules.munged .gitmodules &&
 	git commit -am "drop protection"
 '
 
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 14c41b2cb7c..cdc1d6fcc78 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
+test_expect_success 'status -z implies porcelain' '
 	git status --porcelain |
-	perl -pe "s/\012/\000/g" >expect &&
+	tr "\012" "\000" >expect &&
 	git status -z >output &&
 	test_cmp expect output
 '
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 5cb16872081..db1e2afb2ca 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,12 +4,6 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping blame textconv tests; Perl not available'
-	test_done
-fi
-
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
@@ -17,7 +11,7 @@ find_blame() {
 cat >helper <<'EOF'
 #!/bin/sh
 grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
-"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
+sed 's/^bin: /converted: /' "$1"
 EOF
 chmod +x helper
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index a9d38be997c..b57a362bb98 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
+test_expect_success '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
 	(cd tmp &&
-		perl -i.bak -p -e "s/^58$/5588/" file &&
-		perl -i.bak -p -e "s/^61$/6611/" file &&
+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" file >file.munged &&
+		mv file.munged file &&
 		poke file &&
 		test x"$(sed -n -e 58p < file)" = x5588 &&
 		test x"$(sed -n -e 61p < file)" = x6611 &&
@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
+test_expect_success 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
-	perl -i.bak -p -e 's/^4\$/4444/' file &&
-	perl -i.bak -p -e 's/^7\$/7777/' file &&
+	sed -e 's/^4\$/4444/' \
+	    -e 's/^7\$/7777/' \
+		file >file.munged &&
+	mv file.munged file &&
 	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
 	git commit -m '4 => 4444, 7 => 7777' file &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 12/20] t: refactor tests depending on Perl to print data
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (10 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 18:35     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
                     ` (9 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A bunch of tests rely on Perl to print data in various different ways.
These usages fall into the following categories:

  - Print data conditionally by matching patterns. These usecases can be
    converted to use awk(1) rather easily.

  - Print data repeatedly. These usecases can typically be converted to
    use a combination of `test-tool genzeros` and sed(1).

  - Print data in reverse. These usecases can be converted to use
    awk(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0610-reftable-basics.sh          |  7 +++----
 t/t0613-reftable-write-options.sh   |  4 ++--
 t/t1010-mktree.sh                   |  8 ++++----
 t/t4150-am.sh                       | 10 +++++-----
 t/t5300-pack-object.sh              | 16 +++++-----------
 t/t5326-multi-pack-bitmaps.sh       |  6 +++---
 t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------
 t/t5410-receive-pack-alternates.sh  |  6 +++---
 t/t5701-git-serve.sh                |  7 +++++--
 t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------
 t/t6115-rev-list-du.sh              |  8 +-------
 t/t7006-pager.sh                    |  8 ++++----
 t/t8002-blame.sh                    |  2 +-
 t/t9850-shell.sh                    |  4 ++--
 14 files changed, 51 insertions(+), 67 deletions(-)

diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 5e0a1fa176d..77ed11e7172 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
+test_expect_success 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+
+	awk "BEGIN { for (i = 0; i < 50000; i++) printf \"%s\", \"this is a long commit message\" }" >commit-msg &&
 	git -C repo commit --allow-empty --file=../commit-msg
 '
 
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index fa1e2f9eef8..42aa1592f87 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
+test_expect_success 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
 		cd repo &&
 		test_commit A &&
-		perl -e "print \"a\" x 500" >logmsg &&
+		test-tool genzeros 500 | tr "\000" "a" >logmsg &&
 		cat >expect <<-EOF &&
 		fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large
 		EOF
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 4977998e205..e9973f74949 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
-	perl -e "print reverse <>" <top |
+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+	sort -r <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
-	perl -e "print reverse <>" <top.withsub |
+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+	sort -r <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
 '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 4794510d70d..2ae93d3c967 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
+test_expect_success 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'
     Body test" --author="$LONG <long@example.com>" &&
 	git format-patch --stdout -1 >patch &&
 	# bump from, date, and subject down to in-body header
-	perl -lpe "
-		if (/^From:/) {
+	awk "
+		/^From:/{
 			print \"From: x <x\@example.com>\";
 			print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
 			print \"Subject: x\n\";
-		}
-	" patch >msg &&
+		}; 1
+	" <patch >msg &&
 	git checkout HEAD^ &&
 	git am msg &&
 	# Ensure that the author and full message are present
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 143856c29f1..a5932b6a8be 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,17 +7,11 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pack-object tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	rm -f .git/index* &&
-	perl -e "print \"a\" x 4096;" >a &&
-	perl -e "print \"b\" x 4096;" >b &&
-	perl -e "print \"c\" x 4096;" >c &&
+	test-tool genzeros 4096 | tr "\000" "a" >a &&
+	test-tool genzeros 4096 | tr "\000" "b" >b &&
+	test-tool genzeros 4096 | tr "\000" "c" >c &&
 	test-tool genrandom "seed a" 2097152 >a_big &&
 	test-tool genrandom "seed b" 2097152 >b_big &&
 	git update-index --add a a_big b b_big c &&
@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'
 # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>
 # e.g.: check_deltas stderr -gt 0
 check_deltas() {
-	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' "$1") &&
 	shift &&
 	if ! test "$deltas" "$@"
 	then
@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '
 	check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
 '
 
-test_expect_success 'compare delta flavors' '
+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '
 	perl -e '\''
 		defined($_ = -s $_) or die for @ARGV;
 		exit 1 if $ARGV[0] <= $ARGV[1];
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 627f8b4efdc..892aeb09e4b 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {
 			comm -13 bitmaps commits >before &&
 			test_line_count = 1 before &&
 
-			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
-				<before | git update-ref --stdin &&
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
+			git update-ref --stdin &&
 
 			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
 			rm -fr $midx &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 1059ff45fe4..56674db562f 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
-	test_done
-fi
-
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {
 
 tag_everything () {
 	git rev-list --all --no-object-names >in &&
-	perl -lne '
-		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
-	' <in | git update-ref --stdin
+	sed 's|\(.*\)|create refs/tags/\1 \1|' in |
+	git update-ref --stdin
 }
 
 test_expect_success 'setup' '
@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '
 	test_cmp expect actual
 '
 
-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
 	test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
 	test_config bitmapPseudoMerge.test.maxMerges 1 &&
 	test_config bitmapPseudoMerge.test.stableThreshold never &&
@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 			test_commit_bulk 16 &&
 
 			git rev-list HEAD~16.. >in &&
-
-			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" in |
 			git update-ref --stdin || return 1
 		done &&
 
@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 		do
 			test_pseudo_merge_commits $m >oids &&
 			grep -f oids refs |
-			perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
+			sed -n "s|refs/remotes/\([0-9][0-9]*\)/|\1|p" &&
 			sort -u || return 1
 		done >remotes &&
 
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 6a009fdcd71..4e82fd102e3 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -17,10 +17,10 @@ test_expect_success 'setup' '
 '
 
 extract_haves () {
-	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+	depacketize | sed -n 's/^\([^ ][^ ]*\) \.have/\1/p'
 }
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
+test_expect_success 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
+test_expect_success 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 200bf06ecb3..d4c28bae39e 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
+test_expect_success 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 		echo command=ls-refs &&
 		echo object-format=$(test_oid algo) &&
 		echo 0001 &&
-		perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
+		awk "{
+			for (i = 1; i <= 65536; i++)
+				print \"ref-prefix refs/heads/\", \$i
+		}" &&
 		echo 0000
 	} |
 	test-tool pkt-line pack >in &&
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 8074185742c..273196f52b5 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
-	git rev-list --parents --full-history main -- foo |
-		perl -e "print reverse <>" > expected &&
+reverse () {
+	awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'
+}
+
+test_expect_success '--reverse --parents --full-history combines correctly' '
+	git rev-list --parents --full-history main -- foo | reverse >expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
 		> actual &&
 	test_cmp expected actual
 	'
 
-test_expect_success PERL_TEST_HELPERS '--boundary does too' '
-	git rev-list --boundary --parents --full-history main ^root -- foo |
-		perl -e "print reverse <>" > expected &&
+test_expect_success '--boundary does too' '
+	git rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&
 	git rev-list --boundary --reverse --parents --full-history \
 		main ^root -- foo > actual &&
 	test_cmp expected actual
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 6a74be576a2..04c577dad69 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list disk usage tests; Perl not available'
-	test_done
-fi
-
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '
 disk_usage_slow () {
 	git rev-list --no-object-names "$@" |
 	git cat-file --batch-check="%(objectsize:disk)" |
-	perl -lne '$total += $_; END { print $total}'
+	awk '{ i += $1 } END { print i }'
 }
 
 # check behavior with given rev-list options; note that
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 49aae183829..9717e825f0d 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success PERL_TEST_HELPERS 'setup large log output' '
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+test_expect_success 'setup large log output' '
+	test-tool genzeros 50000 |
+	tr "\000" "a" |
+	sed "s/a/this is a long commit message/g" >commit-msg &&
 	git commit --allow-empty -F commit-msg
 '
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index b40199df231..7822947f028 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '
 		expect=$1 && shift &&
 		echo $sha1 | cut -c 1-$expect >expect &&
 		git blame "$@" abbrev.t >actual &&
-		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" actual >actual.sha &&
 		test_cmp expect actual.sha
 	}
 '
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index f619b60f226..21c3af48bd0 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
-	perl -e "print \"a\" x 2**12 for (0..2**19)" |
+test_expect_success 'shell complains of overlong commands' '
+	test-tool genzeros | tr "\000" "a" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (11 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 18:55     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
                     ` (8 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of tests that depend on Perl for textconv scripts.
Refactor these tests to instead be implemented via shell utilities so
that we can drop a couple of PERL_TEST_HELPERS prerequisites.

Note that not all of the conversions are a one-to-one equivalent to the
previous textconv scripts. But that's not really needed in the first
place: we only care that the textconv script does something, and that
can be verified trivially without having a full-blown invocation of
hexdump. So at times, the implementation of the textconv scripts is
reduced to their bare minimum and the expectations of those tests are
adapted accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t4030-diff-textconv.sh       | 15 +++------------
 t/t4031-diff-rewrite-binary.sh | 19 +++++++------------
 t/t7815-grep-binary.sh         | 15 +++------------
 3 files changed, 13 insertions(+), 36 deletions(-)

diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index c7d8eb12453..f904fc19f69 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping diff textconv tests; Perl not available'
-	test_done
-fi
-
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
 +1
 EOF
 
-cat >hexdump <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-chmod +x hexdump
-
 test_expect_success 'setup binary file with history' '
+	write_script hexdump <<-\EOF &&
+	tr "\000\001" "01" <"$1"
+	EOF
 	test_commit --printf one file "\\0\\n" &&
 	test_commit --printf --append two file "\\01\\n"
 '
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index cbe50b15772..15e012ccc7c 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
 	grep " rewrite file" diff
 '
 
-{
-	echo "#!$SHELL_PATH"
-	cat <<'EOF'
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-} >dump
-chmod +x dump
-
 test_expect_success 'setup textconv' '
+	write_script dump <<-\EOF &&
+	test-tool hexdump <"$1"
+	EOF
 	echo file diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
+test_expect_success 'rewrite diff respects textconv' '
 	git diff -B >diff &&
-	grep "dissimilarity index" diff &&
-	grep "^-61" diff &&
-	grep "^-0" diff
+	test_grep "dissimilarity index" diff &&
+	test_grep "^-3d 0a 00" diff &&
+	test_grep "^+3d 0a 01" diff
 '
 
 test_done
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index b2730d200c8..3bd91da9707 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,12 +4,6 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping grep binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
 	test_cmp expect actual
 '
 
-cat >nul_to_q_textconv <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
-EOF
-chmod +x nul_to_q_textconv
-
 test_expect_success 'setup textconv filters' '
+	write_script nul_to_q_textconv <<-\EOF &&
+	tr "\000" "Q" <"$1"
+	EOF
 	echo a diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
 '

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (12 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 18:56     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
                     ` (7 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
stdin. Refactor it to instead use awk(1) so that we drop the
PERL_TEST_HELPERS prerequisite in users of this library.

Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
now that the test suite doesn't bail out early anymore in case the
prerequisite isn't set.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-gpg.sh            |  6 +-----
 t/t6300-for-each-ref.sh | 21 ++++++++++-----------
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 3845b6ac449..937b876bd05 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '
 '
 
 sanitize_pgp() {
-	perl -ne '
-		/^-----END PGP/ and $in_pgp = 0;
-		print unless $in_pgp;
-		/^-----BEGIN PGP/ and $in_pgp = 1;
-	'
+	sed "/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}"
 }
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 732a4d3171e..5db7038c417 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping for-each-ref tests; Perl not available'
-	test_done
-fi
-
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '
 	test_must_fail git for-each-ref --format="%(raw)" --tcl
 '
 
-test_expect_success '%(raw) with --perl' '
+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
 	git for-each-ref --format="\$name= %(raw);
 print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
 	cmp blob1 actual &&
@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '
 '
 
 test_trailer_option () {
+	if test "$#" -eq 3
+	then
+		prereq="$1"
+		shift
+	fi &&
 	title=$1 option=$2
 	cat >expect
-	test_expect_success "$title" '
+	test_expect_success $prereq "$title" '
 		git for-each-ref --format="%($option)" refs/heads/main >actual &&
 		test_cmp expect actual &&
 		git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
@@ -1452,7 +1451,7 @@ test_trailer_option () {
 	'
 }
 
-test_trailer_option '%(trailers:unfold) unfolds trailers' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
 	'trailers:unfold' <<-EOF
 	$(unfold <trailers)
 
@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \
 
 	EOF
 
-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
 	'trailers:only,unfold' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 
 	EOF
 
-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
 	'trailers:unfold,only' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (13 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
                     ` (6 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `name_from_description()` test helper uses Perl to munge a given
description and convert it into a name. Refactor it to instead use a
combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
prerequisites in users of this library.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-t6000.sh                 | 13 ++++++-------
 t/t6002-rev-list-bisect.sh     |  6 ------
 t/t6003-rev-list-topo-order.sh |  6 ------
 3 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
index fba6778ca35..35c54724650 100644
--- a/t/lib-t6000.sh
+++ b/t/lib-t6000.sh
@@ -109,13 +109,12 @@ check_output () {
 # All alphanums translated into -'s which are then compressed and stripped
 # from front and back.
 name_from_description () {
-	perl -pe '
-		s/[^A-Za-z0-9.]/-/g;
-		s/-+/-/g;
-		s/-$//;
-		s/^-//;
-		y/A-Z/a-z/;
-	'
+	sed \
+		-e 's/[^A-Za-z0-9.]/-/g' \
+		-e 's/--*/-/g' \
+		-e 's/-$//' \
+		-e 's/^-//' \
+		-e 'y/A-Z/a-z/'
 }
 
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index 5e1482aff78..daa009c9a1b 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list bisect tests; Perl not available'
-	test_done
-fi
-
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 02dd4127aff..0d7055d46d4 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list topo-order tests; Perl not available'
-	test_done
-fi
-
 list_duplicates()
 {
     "$@" | sort | uniq -d

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 16/20] t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (14 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
                     ` (5 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our Apache HTTPD setup exposes an "one_time_perl" endpoint to access
repositories. If used, we execute the "apply-one-time-perl.sh" CGI
script that checks whether we have a "one-time-perl" script. If so, that
script gets executed so that it can munge what would be served. Once
done, the script gets removed so that it doesn't execute a second time.

As the name says, this functionality expects the user to pass a Perl
script. This isn't really necessary though: we can just as easily
implement the same thing with arbitrary scripts.

Refactor the code so that we instead expect an arbitrary script to
exist and rename the functionality to "one-time-script". Adapt callers
to use shell utilities instead of Perl so that we can drop the
PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-httpd.sh                       |  2 +-
 t/lib-httpd/apache.conf              |  6 ++---
 t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------
 t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++
 t/t5537-fetch-shallow.sh             | 17 ++++++-------
 t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------
 t/t5702-protocol-v2.sh               | 27 +++++++++++---------
 t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---
 8 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index d83bafeab32..5091db949b7 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -165,7 +165,7 @@ prepare_httpd() {
 	install_script broken-smart-http.sh
 	install_script error-smart-http.sh
 	install_script error.sh
-	install_script apply-one-time-perl.sh
+	install_script apply-one-time-script.sh
 	install_script nph-custom-auth.sh
 
 	ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 022276a6b9a..e631ab0eb5e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
-<LocationMatch /one_time_perl/>
+<LocationMatch /one_time_script/>
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1
 ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Directory ${GIT_EXEC_PATH}>
 	Options FollowSymlinks
@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Files error.sh>
   Options ExecCGI
 </Files>
-<Files apply-one-time-perl.sh>
+<Files apply-one-time-script.sh>
 	Options ExecCGI
 </Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
deleted file mode 100644
index d7f9fed6aee..00000000000
--- a/t/lib-httpd/apply-one-time-perl.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# If "one-time-perl" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,
-# using the contents of "one-time-perl" as the perl command to be run. If the
-# response was modified as a result, delete "one-time-perl" so that subsequent
-# HTTP responses are no longer modified.
-#
-# This can be used to simulate the effects of the repository changing in
-# between HTTP request-response pairs.
-if test -f one-time-perl
-then
-	LC_ALL=C
-	export LC_ALL
-
-	"$GIT_EXEC_PATH/git-http-backend" >out
-	"$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
-
-	if cmp -s out out_modified
-	then
-		cat out
-	else
-		cat out_modified
-		rm one-time-perl
-	fi
-else
-	"$GIT_EXEC_PATH/git-http-backend"
-fi
diff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh
new file mode 100644
index 00000000000..b1682944e28
--- /dev/null
+++ b/t/lib-httpd/apply-one-time-script.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# If "one-time-script" exists in $HTTPD_ROOT_PATH, run the script on the HTTP
+# response. If the response was modified as a result, delete "one-time-script"
+# so that subsequent HTTP responses are no longer modified.
+#
+# This can be used to simulate the effects of the repository changing in
+# between HTTP request-response pairs.
+if test -f one-time-script
+then
+	LC_ALL=C
+	export LC_ALL
+
+	"$GIT_EXEC_PATH/git-http-backend" >out
+	./one-time-script out >out_modified
+
+	if cmp -s out out_modified
+	then
+		cat out
+	else
+		cat out_modified
+		rm one-time-script
+	fi
+else
+	"$GIT_EXEC_PATH/git-http-backend"
+fi
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 77d20d19110..6588ce62264 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before
 	git -C "$REPO" config protocol.version 2 &&
 	git -C client config protocol.version 2 &&
 
-	git -C client fetch --depth=2 "$HTTPD_URL/one_time_perl/repo" main:a_branch &&
+	git -C client fetch --depth=2 "$HTTPD_URL/one_time_script/repo" main:a_branch &&
 
 	# Craft a situation in which the server sends back an unshallow request
 	# with an empty packfile. This is done by refetching with a shorter
 	# depth (to ensure that the packfile is empty), and overwriting the
 	# shallow line in the response with the unshallow line we want.
-	printf "$(test_oid perl)" \
-	       "$(git -C "$REPO" rev-parse HEAD)" \
-	       "$(git -C "$REPO" rev-parse HEAD^)" \
-	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" "\$1"
+	EOF
 	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
-		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
+		fetch --depth=1 "$HTTPD_URL/one_time_script/repo" \
 		main:a_branch &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl" &&
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script" &&
 
 	# Ensure that the resulting repo is consistent, despite our failure to
 	# fetch.
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index bc7e0fec8dc..1e354e057fa 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -737,21 +737,25 @@ intersperse () {
 	sed 's/\(..\)/'$1'\1/g'
 }
 
-# Create a one-time-perl command to replace the existing packfile with $1.
+# Create a one-time-script command to replace the existing packfile with $1.
 replace_packfile () {
-	# The protocol requires that the packfile be sent in sideband 1, hence
-	# the extra \x01 byte at the beginning.
-	cp $1 "$HTTPD_ROOT_PATH/one-time-pack" &&
-	echo 'if (/packfile/) {
-		print;
-		my $length = -s "one-time-pack";
-		printf "%04x\x01", $length + 5;
-		print `cat one-time-pack` . "0000";
-		last
-	}' >"$HTTPD_ROOT_PATH/one-time-perl"
+	cp "$1" one-time-pack &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	if grep packfile "\$1" >/dev/null
+	then
+		sed '/packfile/q' "\$1" &&
+		# The protocol requires that the packfile be sent in sideband
+		# 1, hence the extra \001 byte at the beginning.
+		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
+		cat "$PWD/one-time-pack" &&
+		printf "0000"
+	else
+		cat "\$1"
+	fi
+	EOF
 }
 
-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
+test_expect_success 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t
 	# section header.
 	test_config -C "$SERVER" protocol.version 2 &&
 	test_must_fail git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&
 
 	test_grep "did not send all necessary objects" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not
 
 	# Exercise to make sure it works.
 	git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&
 	! grep "missing object referenced by" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 
 	# Clone. The client has deltabase_have but not deltabase_missing.
 	git -c protocol.version=2 clone --no-checkout \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo &&
 	git -C repo hash-object -w -- "$SERVER/have.txt" &&
 
 	# Sanity check to ensure that the client does not have
@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 	grep "want $(cat deltabase_missing)" trace &&
 	! grep "want $(cat deltabase_have)" trace &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 # DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ad5e772cd72..8548854f32e 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
+test_expect_success 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM'
 
 	# After "ready" in the acknowledgments section, pretend that a FLUSH
 	# (0000) was sent instead of a DELIM (0001).
-	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/ready/{n;s/0001/0000/;}" "$1"
+	EOF
 
 	test_must_fail git -C http_child -c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
+test_expect_success 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect
 
 	# After the acknowledgments section, pretend that a DELIM
 	# (0001) was sent instead of a FLUSH (0000).
-	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/acknowledgments/,//{s/0000/0001/;}" "$1"
+	EOF
 
 	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
 		-c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	grep "fetch< .*acknowledgments" log &&
 	! grep "fetch< .*ready" log &&
 	test_grep "expected no other sections to be sent after no .ready." err
@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
-	URI="$HTTPD_URL/one_time_perl/server" &&
+	URI="$HTTPD_URL/one_time_script/server" &&
 
 	setup_negotiate_only "$SERVER" "$URI" &&
 
-	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" "$1"
+	EOF
 
 	test_must_fail git -c protocol.version=2 -C client fetch \
 		--no-tags \
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index f59d47aa6c6..fc915e7b823 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '
 		test_commit m3 &&
 		git tag -d m2 m3
 	) &&
-	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo" &&
+	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo" &&
 	git -C "$LOCAL_PRISTINE" config protocol.version 2
 '
 
@@ -481,7 +481,9 @@ inconsistency () {
 	# RPCs during a single negotiation.
 	oid1=$(git -C "$REPO" rev-parse $1) &&
 	oid2=$(git -C "$REPO" rev-parse $2) &&
-	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	sed "s/$oid1/$oid2/" "\$1"
+	EOF
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
-	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/main/rain/" "$1"
+	EOF
 	test_must_fail git -C local fetch 2>err &&
 
 	test_grep "fatal: remote error: unknown ref refs/heads/rain" err

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (15 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-04-01 19:04     ` Johannes Schindelin
  2025-03-27 10:37   ` [PATCH v3 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
                     ` (4 subsequent siblings)
  21 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `generate_random_characters()` helper function generates N
random characters in the range 'a-z' and writes them into a file. The
logic currently uses Perl, but it can be adapted rather easily by:

  - Making `test-tool genrandom` generate an infinite stream.

  - Using `tr -dc` to strip all characters which aren't in the range of
    'a-z'.

  - Using `test_copy_bytes()` to copy the first N bytes.

This allows us to drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 4a892a91780..bf10d253ec4 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -20,8 +20,7 @@ EOF
 generate_random_characters () {
 	LEN=$1
 	NAME=$2
-	test-tool genrandom some-seed $LEN |
-		perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
+	test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME"
 }
 
 filter_git () {
@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
+test_expect_success 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
+test_expect_success 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 18/20] t0210: refactor trace2 scrubbing to not use Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (16 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
                     ` (3 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The output generated by our trace2 mechanism contains several fields
that are dependent on the environment they're being run in, which makes
it somewhat harder to test it. As a countermeasure we scrub the output
and strip out any fields that contain such information.

The logic to do so is implemented in Perl, but it can be trivially
ported to instead use sed(1). Refactor the code accordingly so that we
can drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------
 t/t0210/scrub_normal.perl | 54 -----------------------------------------
 2 files changed, 43 insertions(+), 72 deletions(-)

diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index ba4c0442b85..96c68f65df2 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping trace2 tests; Perl not available'
-	test_done
-fi
-
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF
 #
 # Implicit return from cmd_<verb> function propagates <code>.
 
+scrub_normal () {
+	# Scrub the variable fields from the normal trace2 output to make
+	# testing easier:
+	#
+	#   1. Various messages include an elapsed time in the middle of the
+	#      message. Replace the time with a placeholder to simplify our
+	#      HEREDOC in the test script.
+	#
+	#   2. We expect:
+	#
+	#        start <argv0> [<argv1> [<argv2> [...]]]
+	#
+	#      where argv0 might be a relative or absolute path, with or
+	#      without quotes, and platform dependent. Replace argv0 with a
+	#      token for HEREDOC matching in the test script.
+	#
+	#   3. Likewise, the 'cmd_path' message breaks out argv[0].
+	#
+	#      This line is only emitted when RUNTIME_PREFIX is defined,
+	#      so just omit it for testing purposes.
+	#
+	#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's
+	#      sake, skip it when parsing normal.
+	sed \
+		-e 's/elapsed:[0-9]*\.[0-9][0-9]*\([eE][-+]\{0,1\}[0-9][0-9]*\)\{0,1\}/elapsed:_TIME_/g' \
+		-e "s/^start '[^']*' \(.*\)/start _EXE_ \1/" \
+		-e 's/^start [^ ][^ ]* \(.*\)/start _EXE_ \1/' \
+		-e '/^cmd_path/d' \
+		-e '/^cmd_ancestry/d'
+}
+
 test_expect_success 'normal stream, return code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '
 test_expect_success 'normal stream, return code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 1
@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '
 	test_when_finished "rm -r traces actual expect" &&
 	mkdir traces &&
 	GIT_TRACE2="$(pwd)/traces" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <"$(ls traces/*)" >actual &&
+	scrub_normal <"$(ls traces/*)" >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '
 test_expect_success 'normal stream, exit code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 0
@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '
 test_expect_success 'normal stream, exit code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 1
@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '
 test_expect_success 'normal stream, error event' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\''
@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '
 test_expect_success 'BUG messages are written to trace2' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 007bug &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 007bug
@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 008bug
@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 009bug_BUG
@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 010bug_BUG
@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '
 	test_config_global trace2.normalBrief 1 &&
 	test_config_global trace2.normalTarget "$(pwd)/trace.normal" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '
 	mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" &&
 	test_config_global include.path "$(pwd)/real.gitconfig" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl
deleted file mode 100644
index 7cc4de392a0..00000000000
--- a/t/t0210/scrub_normal.perl
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/perl
-#
-# Scrub the variable fields from the normal trace2 output to
-# make testing easier.
-
-use strict;
-use warnings;
-
-my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?';
-
-# This code assumes that the trace2 data was written with bare
-# turned on (which omits the "<clock> <file>:<line>" prefix.
-
-while (<>) {
-    # Various messages include an elapsed time in the middle
-    # of the message.  Replace the time with a placeholder to
-    # simplify our HEREDOC in the test script.
-    s/elapsed:$float/elapsed:_TIME_/g;
-
-    my $line = $_;
-
-    # we expect:
-    #    start <argv0> [<argv1> [<argv2> [...]]]
-    #
-    # where argv0 might be a relative or absolute path, with
-    # or without quotes, and platform dependent.  Replace argv0
-    # with a token for HEREDOC matching in the test script.
-
-    if ($line =~ m/^start/) {
-	$line =~ /^start\s+(.*)/;
-	my $argv = $1;
-	$argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/;
-	my $argv_0 = $1;
-	my $argv_rest = $2;
-
-	print "start _EXE_ $argv_rest\n";
-    }
-    elsif ($line =~ m/^cmd_path/) {
-	# Likewise, the 'cmd_path' message breaks out argv[0].
-	#
-	# This line is only emitted when RUNTIME_PREFIX is defined,
-	# so just omit it for testing purposes.
-	# print "cmd_path _EXE_\n";
-    }
-    elsif ($line =~ m/^cmd_ancestry/) {
-	# 'cmd_ancestry' is not implemented everywhere, so for portability's
-	# sake, skip it when parsing normal.
-	#
-	# print "$line";
-    }
-    else {
-	print "$line";
-    }
-}

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 19/20] t5316: refactor `max_chain()` to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (17 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-27 10:37   ` [PATCH v3 20/20] t5703: refactor test " Patrick Steinhardt
                     ` (2 subsequent siblings)
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `max_chain()` helper function is used to extract the maximum delta
chain of a packfile as printed by git-index-pack(1). The script uses
Perl to extract that data, but it can be trivially refactored to use
awk(1) instead.

Refactor the helper accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5316-pack-delta-depth.sh | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index cd947b5a5ef..defaa06d650 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '
 
 max_chain() {
 	git index-pack --verify-stat-only "$1" >output &&
-	perl -lne '
-	  BEGIN { $len = 0 }
-	  /chain length = (\d+)/ and $len = $1;
-	  END { print $len }
-	' output
+	awk '
+		BEGIN { len=0 }
+		/chain length = [0-9]+:/{ len=$4 }
+		END { print len }
+	' <output | tr -d ':'
 }
 
 # Note that this whole setup is pretty reliant on the current
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
+test_expect_success 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
+test_expect_success '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
+test_expect_success '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
+test_expect_success 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 20/20] t5703: refactor test to not depend on Perl
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (18 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
@ 2025-03-27 10:37   ` Patrick Steinhardt
  2025-03-28 10:29   ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Phillip Wood
  2025-04-02 19:32   ` Johannes Schindelin
  21 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-03-27 10:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We use Perl due to two different reasons in t5703:

  - To filter advertised capabilities.

  - To set up a CGI script with HTTPD.

Refactor the first category to use `test_grep` instead. Refactoring the
second category would be a bit more involved, so instead we add the
PERL_TEST_HELPERS prerequisite to those individual tests now.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index fc915e7b823..249137b4673 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
-	test_done
-fi
-
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '
 
 test_expect_success 'config controls ref-in-want advertisement' '
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant false &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant true &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_file_not_empty out.filter
+	test_grep "ref-in-want" out
 '
 
 test_expect_success 'invalid want-ref line' '
@@ -486,7 +477,7 @@ inconsistency () {
 	EOF
 }
 
-test_expect_success 'server is initially ahead - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
 	test_grep "fatal: remote error: upload-pack: not our ref" err
 '
 
-test_expect_success 'server is initially ahead - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server loses a ref - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&

-- 
2.49.0.472.ge94155a9ec.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (19 preceding siblings ...)
  2025-03-27 10:37   ` [PATCH v3 20/20] t5703: refactor test " Patrick Steinhardt
@ 2025-03-28 10:29   ` Phillip Wood
  2025-04-02 19:32   ` Johannes Schindelin
  21 siblings, 0 replies; 121+ messages in thread
From: Phillip Wood @ 2025-03-28 10:29 UTC (permalink / raw)
  To: Patrick Steinhardt, git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak

Hi Patrick

On 27/03/2025 10:36, Patrick Steinhardt wrote:
> 
> Changes in v3:
>    - Remove more useless indirections for sed(1).

Thanks for removing these, the range-diff below looks good

Best Wishes

Phillip

> Range-diff versus v2:
> 
>   1:  8c98b24fe4c =  1:  f2fe08ef0ff t: skip chain lint when PERL_PATH is unset
>   2:  f140153954c =  2:  9dd2edd0a1a t: refactor environment sanitization to not use Perl
>   3:  94b5591f666 =  3:  c77424e6907 t: adapt character translation helpers to not use Perl
>   4:  a5880fdb8ef =  4:  476d1b15932 t: adapt `test_copy_bytes()` to not use Perl
>   5:  3b64c99c061 =  5:  14badee2551 t: adapt `test_readlink()` to not use Perl
>   6:  a3536260e4c =  6:  9a88a46bd10 t: introduce PERL_TEST_HELPERS prerequisite
>   7:  98961b0e065 =  7:  e7413bf28ae t: adapt existing PERL prerequisites
>   8:  bbdd1fe6c7c =  8:  581a9bedd22 meson: stop requiring Perl when tests are enabled
>   9:  bda7e7922ce =  9:  cfe1797ae74 Makefile: stop requiring Perl when running tests
> 10:  d95d50c4b73 = 10:  99e678b83a6 t: refactor tests depending on Perl transliteration operator
> 11:  f5b30cc3f8f ! 11:  93a98d3e3cf t: refactor tests depending on Perl substitution operator
>      @@ t/t4029-diff-trailing-space.sh: test_expect_success PERL_TEST_HELPERS "$test_des
>        	git diff f > actual &&
>        	test_cmp exp actual &&
>       -	perl -i.bak -p -e "s/^\$/ /" exp &&
>      -+	sed "s/^\$/ /" <exp >exp.munged &&
>      ++	sed "s/^\$/ /" exp >exp.munged &&
>       +	mv exp.munged exp &&
>        	git config --bool diff.suppressBlankEmpty false &&
>        	git diff f > actual &&
>      @@ t/t4200-rerere.sh: test_expect_success 'activate rerere, old style (conflicting
>        	test_must_fail git merge first &&
>        
>       -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
>      -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>      ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
>        	rr=.git/rr-cache/$sha1 &&
>        	grep "^=======\$" $rr/preimage &&
>        	! test -f $rr/postimage &&
>      @@ t/t4200-rerere.sh: test_expect_success 'rerere.enabled works, too' '
>        	test_must_fail git merge first &&
>        
>       -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
>      -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>      ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
>        	rr=.git/rr-cache/$sha1 &&
>        	grep ^=======$ $rr/preimage
>        '
>      @@ t/t4200-rerere.sh: test_expect_success 'set up rr-cache' '
>        	git reset --hard &&
>        	test_must_fail git merge first &&
>       -	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
>      -+	sha1=$(sed "s/	.*//" <.git/MERGE_RR) &&
>      ++	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
>        	rr=.git/rr-cache/$sha1
>        '
>        
>      @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and loose copy o
>        	git prune-packed &&
>        	chmod +w ${pack}.pack &&
>       -	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
>      -+	sed "s/ base /abcdef/" <${pack}.pack >${pack}.pack.munged &&
>      ++	sed "s/ base /abcdef/" ${pack}.pack >${pack}.pack.munged &&
>       +	mv ${pack}.pack.munged ${pack}.pack &&
>        	test_must_fail git cat-file blob $blob_1 > /dev/null &&
>        	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>      @@ t/t5303-pack-corruption-resilience.sh: test_expect_success '... and then a repac
>        	git prune-packed &&
>        	chmod +w ${pack}.pack &&
>       -	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
>      -+	sed "s/ delta1 /abcdefgh/" <${pack}.pack >${pack}.pack.munged &&
>      ++	sed "s/ delta1 /abcdefgh/" ${pack}.pack >${pack}.pack.munged &&
>       +	mv ${pack}.pack.munged ${pack}.pack &&
>        	git cat-file blob $blob_1 > /dev/null &&
>        	test_must_fail git cat-file blob $blob_2 > /dev/null &&
>      @@ t/t5310-pack-bitmaps.sh: test_bitmap_cases () {
>        			# mark the commits which did not receive bitmaps as preferred,
>        			# and generate the bitmap again
>       -			perl -pe "s{^}{create refs/tags/include/$. }" <before |
>      -+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
>      ++			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
>        				git update-ref --stdin &&
>        			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
>        
>      @@ t/t5534-push-signed.sh: test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent
>        	# different, then replay it on a fresh dst, checking that ff is not
>        	# deleted.
>       -	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
>      -+	sed "s/\([^ ]\)bar/\1baz/" <push >push.tweak &&
>      ++	sed "s/\([^ ]\)bar/\1baz/" push >push.tweak &&
>        	prepare_dst &&
>        	git -C dst config receive.certnonceseed sekrit &&
>        	git -C dst config receive.advertisepushoptions 1 &&
>      @@ t/t6011-rev-list-with-bad-commit.sh: test_expect_success 'verify number of revis
>       +test_expect_success 'corrupt second commit object' '
>       +	for p in .git/objects/pack/*.pack
>       +	do
>      -+		sed "s/second commit/socond commit/" <"$p" >"$p.munged" &&
>      ++		sed "s/second commit/socond commit/" "$p" >"$p.munged" &&
>       +		mv "$p.munged" "$p" ||
>       +		return 1
>       +	done &&
>      @@ t/t7416-submodule-dash-url.sh: test_expect_success 'fsck accepts protected dash'
>        
>        test_expect_success 'remove ./ protection from .gitmodules url' '
>       -	perl -i -pe "s{\./}{}" .gitmodules &&
>      -+	sed "s|\./||" <.gitmodules >.gitmodules.munged &&
>      ++	sed "s|\./||" .gitmodules >.gitmodules.munged &&
>       +	mv .gitmodules.munged .gitmodules &&
>        	git commit -am "drop protection"
>        '
>      @@ t/t8006-blame-textconv.sh: find_blame() {
>        #!/bin/sh
>        grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
>       -"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
>      -+sed 's/^bin: /converted: /' <"$1"
>      ++sed 's/^bin: /converted: /' "$1"
>        EOF
>        chmod +x helper
>        
>      @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'initialize repo'
>        	(cd tmp &&
>       -		perl -i.bak -p -e "s/^58$/5588/" file &&
>       -		perl -i.bak -p -e "s/^61$/6611/" file &&
>      -+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" <file >file.munged &&
>      ++		sed -e "s/^58$/5588/" -e "s/^61$/6611/" file >file.munged &&
>       +		mv file.munged file &&
>        		poke file &&
>        		test x"$(sed -n -e 58p < file)" = x5588 &&
>      @@ t/t9137-git-svn-dcommit-clobber-series.sh: test_expect_success 'some unrelated c
>       -	perl -i.bak -p -e 's/^7\$/7777/' file &&
>       +	sed -e 's/^4\$/4444/' \
>       +	    -e 's/^7\$/7777/' \
>      -+		<file >file.munged &&
>      ++		file >file.munged &&
>       +	mv file.munged file &&
>        	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
>        	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
> 12:  e978d8ecfde ! 12:  17f862eaba3 t: refactor tests depending on Perl to print data
>      @@ t/t5300-pack-object.sh: test_expect_success 'pack-object <stdin parsing: --stdin
>        # e.g.: check_deltas stderr -gt 0
>        check_deltas() {
>       -	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
>      -+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' <"$1") &&
>      ++	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' "$1") &&
>        	shift &&
>        	if ! test "$deltas" "$@"
>        	then
>      @@ t/t5326-multi-pack-bitmaps.sh: test_midx_bitmap_cases () {
>        
>       -			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
>       -				<before | git update-ref --stdin &&
>      -+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" <before |
>      ++			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
>       +			git update-ref --stdin &&
>        
>        			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
>      @@ t/t5333-pseudo-merge-bitmaps.sh: test_pseudo_merges_reused () {
>       -	perl -lne '
>       -		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
>       -	' <in | git update-ref --stdin
>      -+	sed 's|\(.*\)|create refs/tags/\1 \1|' <in |
>      ++	sed 's|\(.*\)|create refs/tags/\1 \1|' in |
>       +	git update-ref --stdin
>        }
>        
>      @@ t/t5333-pseudo-merge-bitmaps.sh: test_expect_success 'pseudo-merge pattern with
>        			git rev-list HEAD~16.. >in &&
>       -
>       -			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
>      -+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" <in |
>      ++			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" in |
>        			git update-ref --stdin || return 1
>        		done &&
>        
>      @@ t/t8002-blame.sh: test_expect_success 'set up abbrev tests' '
>        		echo $sha1 | cut -c 1-$expect >expect &&
>        		git blame "$@" abbrev.t >actual &&
>       -		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
>      -+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" <actual >actual.sha &&
>      ++		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" actual >actual.sha &&
>        		test_cmp expect actual.sha
>        	}
>        '
> 13:  905c25c9fb2 = 13:  7b03d096ccd t: refactor tests depending on Perl for textconv scripts
> 14:  1fe67bba30f = 14:  195c0bf2445 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
> 15:  9e572c3ba67 = 15:  e92d178b96b t/lib-t6000: refactor `name_from_description()` to not depend on Perl
> 16:  24abcffe96e ! 16:  0f2c9ad276b t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
>      @@ t/t5537-fetch-shallow.sh: test_expect_success PERL_TEST_HELPERS 'shallow fetches
>       -	       "$(git -C "$REPO" rev-parse HEAD^)" \
>       -	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
>      -+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" <"\$1"
>      ++	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" "\$1"
>       +	EOF
>        	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
>       -		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
>      @@ t/t5616-partial-clone.sh: intersperse () {
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
>       +	if grep packfile "\$1" >/dev/null
>       +	then
>      -+		sed '/packfile/q' <"\$1" &&
>      ++		sed '/packfile/q' "\$1" &&
>       +		# The protocol requires that the packfile be sent in sideband
>       +		# 1, hence the extra \001 byte at the beginning.
>       +		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
>      @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server sends
>       -	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
>       -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
>      -+	sed "/ready/{n;s/0001/0000/;}" <"$1"
>      ++	sed "/ready/{n;s/0001/0000/;}" "$1"
>       +	EOF
>        
>        	test_must_fail git -C http_child -c protocol.version=2 \
>      @@ t/t5702-protocol-v2.sh: test_expect_success PERL_TEST_HELPERS 'when server does
>       -	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
>       -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
>      -+	sed "/acknowledgments/,//{s/0000/0001/;}" <"$1"
>      ++	sed "/acknowledgments/,//{s/0000/0001/;}" "$1"
>       +	EOF
>        
>        	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
>      @@ t/t5702-protocol-v2.sh: test_expect_success 'http:// --negotiate-only' '
>       -	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
>       -		>"$HTTPD_ROOT_PATH/one-time-perl" &&
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
>      -+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" <"$1"
>      ++	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" "$1"
>       +	EOF
>        
>        	test_must_fail git -c protocol.version=2 -C client fetch \
>      @@ t/t5703-upload-pack-ref-in-want.sh: inconsistency () {
>        	oid2=$(git -C "$REPO" rev-parse $2) &&
>       -	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
>      -+	sed "s/$oid1/$oid2/" <"\$1"
>      ++	sed "s/$oid1/$oid2/" "\$1"
>       +	EOF
>        }
>        
>      @@ t/t5703-upload-pack-ref-in-want.sh: test_expect_success 'server loses a ref - re
>        	cp -r "$LOCAL_PRISTINE" local &&
>       -	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
>       +	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
>      -+	sed "s/main/rain/" <"$1"
>      ++	sed "s/main/rain/" "$1"
>       +	EOF
>        	test_must_fail git -C local fetch 2>err &&
>        
> 17:  ce5adbd4818 = 17:  9857b461ed6 t0021: refactor `generate_random_characters()` to not depend on Perl
> 18:  e183c397da9 = 18:  7924b5bd9bf t0210: refactor trace2 scrubbing to not use Perl
> 19:  156bdc4d62d = 19:  5d6996a1412 t5316: refactor `max_chain()` to not depend on Perl
> 20:  3b181d0a203 = 20:  0c3afb70128 t5703: refactor test to not depend on Perl
> 
> ---
> base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
> change-id: 20250317-b4-pks-t-perlless-138cf94696b8
> 
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-03-27 10:37   ` [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-04-01 18:26     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 18:26 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> In the early days of Git, Perl was used quite prominently throughout the
> project. This has changed significantly as almost all of the executables
> we ship nowadays have eventually been rewritten in C. Only a handful of
> subsystems remain that require Perl:
>
>   - gitweb, a read-only web interface.
>
>   - A couple of scripts that allow importing repositories from GNU Arch,
>     CVS and Subversion.
>
>   - git-send-email(1), which can be used to send mails.

There is also `git request-pull` which is a _shell_ script that runs
`perl` to parse the output of `ls-remote`, and there is `git
filter-branch` (which was apparently not yet dropped?) that uses Perl if
the `--state-branch` option is in use.

>   - Our Perl bindings for Git.
>
>   - The netrc Git credential helper.
>
> None of these subsystems can really be considered to be part of the
> "core" of Git, and an installation without them is fully functional.
> It is more likely than not that an end user wouldn't even notice that
> any features are missing if those tools weren't installed. But while
> Perl nowadays very much is an optional dependency of Git, there is a
> significant limitation when Perl isn't available: developers cannot run
> our test suite.
>
> Preceding commits have started to lift this restriction by removing the
> strict dependency on Perl in many central parts of the test library. But
> there are still many tests that rely on small Perl helpers to do various
> different things.
>
> Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
> that require Perl. This prerequisite is explicitly different than the
> preexisting PERL prerequisite:
>
>   - PERL records whether or not features depending on the Perl
>     interpreter are built.
>
>   - PERL_TEST_HELPERS records whether or not a Perl interpreter is
>     available for our tests.
>
> By having these two separate prerequisites we can thus distinguish
> between tests that inherently depend on Perl because the underlying
> feature does, and those tests that depend on Perl because the test
> itself is using Perl.
>
> Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.

The patch looks good, in particular when fetching the `b4/pks-t-perlless`
branch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f
manually, as it is a rather large patch that is pretty much unreviewable
on a mailing list.

Using several write-only `sed` invocations, I identified that there are
only three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`
prereq nor adding a test preamble of this form:

	if ! test_have_prereq PERL_TEST_HELPERS
	then
		skip_all='skipping <something>; Perl not available'
		test_done
	fi

Skipping to only the affected files, these three instances are:

> diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
> index c91a62b77af..342d0423c92 100755
> --- a/t/t5534-push-signed.sh
> +++ b/t/t5534-push-signed.sh
> @@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
>  	test_cmp expect dst/push-cert-status
>  '
>
> -test_expect_success GPG 'inconsistent push options in signed push not allowed' '
> +test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
>  	# First, invoke receive-pack with dummy input to obtain its preamble.
>  	prepare_dst &&
>  	git -C dst config receive.certnonceseed sekrit &&

Here, that prereq is appended.

> diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
> index d0c18660e33..d743d986c40 100755
> --- a/t/t5601-clone.sh
> +++ b/t/t5601-clone.sh
> @@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
>  	git -C replay.git index-pack -v --stdin <tmp.pack
>  '
>
> -test_expect_success 'clone on case-insensitive fs' '
> +test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '
>  	git init icasefs &&
>  	(
>  		cd icasefs &&
> @@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '
>  	)
>  '
>
> -test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
> +test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '
>  	grep X icasefs/warning &&
>  	grep x icasefs/warning &&
>  	test_grep "the following paths have collided" icasefs/warning

Here, too.

> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index a62699d6c79..59162a3c834 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -1706,6 +1706,7 @@ test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
>  test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
>  test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
>  test -n "$GIT_VALGRIND_ENABLED" && test_set_prereq VALGRIND
> +test -n "$PERL_PATH" && test_set_prereq PERL_TEST_HELPERS
>
>  if test -z "$GIT_TEST_CHECK_CACHE_TREE"
>  then

And this is obviously correct, too.

Thank you,
Johannes


^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator
  2025-03-27 10:37   ` [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-04-01 18:32     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 18:32 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> We have a bunch of tests that use Perl to perform substitution via the
> "s/" operator. These usecases can be trivially replaced with sed(1).

... and sometimes `tr`.

In fact, it looks like...

> diff --git a/t/t7508-status.sh b/t/t7508-status.sh
> index 14c41b2cb7c..cdc1d6fcc78 100755
> --- a/t/t7508-status.sh
> +++ b/t/t7508-status.sh
> @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
>  	test_cmp expect output
>  '
>
> -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
> +test_expect_success 'status -z implies porcelain' '
>  	git status --porcelain |
> -	perl -pe "s/\012/\000/g" >expect &&
> +	tr "\012" "\000" >expect &&
>  	git status -z >output &&
>  	test_cmp expect output
>  '

... this change is not about `sed` at all, but only about `tr`.
_Technically_, this hunk would therefore feel more at home in the previous
patch. But practically, I actually do not mind it being here at all.

Thank you,
Johannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 12/20] t: refactor tests depending on Perl to print data
  2025-03-27 10:37   ` [PATCH v3 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-04-01 18:35     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 18:35 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> A bunch of tests rely on Perl to print data in various different ways.
> These usages fall into the following categories:
>
>   - Print data conditionally by matching patterns. These usecases can be
>     converted to use awk(1) rather easily.
>
>   - Print data repeatedly. These usecases can typically be converted to
>     use a combination of `test-tool genzeros` and sed(1).

It might be even more elegant to teach `genzeros` to generate streams of
bytes other than NUL.

>   - Print data in reverse. These usecases can be converted to use
>     awk(1).

Or, in one case, `sort -r`.

These changes all look good to me.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-03-27 10:37   ` [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-04-01 18:55     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 18:55 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

[-- Attachment #1: Type: text/plain, Size: 5443 bytes --]

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> We have a couple of tests that depend on Perl for textconv scripts.
> Refactor these tests to instead be implemented via shell utilities so
> that we can drop a couple of PERL_TEST_HELPERS prerequisites.
>
> Note that not all of the conversions are a one-to-one equivalent to the
> previous textconv scripts. But that's not really needed in the first
> place: we only care that the textconv script does something, and that
> can be verified trivially without having a full-blown invocation of
> hexdump. So at times, the implementation of the textconv scripts is
> reduced to their bare minimum and the expectations of those tests are
> adapted accordingly.

Hmm. I am having a harder time with this patch than with the others. See
below.

>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  t/t4030-diff-textconv.sh       | 15 +++------------
>  t/t4031-diff-rewrite-binary.sh | 19 +++++++------------
>  t/t7815-grep-binary.sh         | 15 +++------------
>  3 files changed, 13 insertions(+), 36 deletions(-)
>
> diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
> index c7d8eb12453..f904fc19f69 100755
> --- a/t/t4030-diff-textconv.sh
> +++ b/t/t4030-diff-textconv.sh
> @@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'
>
>  . ./test-lib.sh
>
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping diff textconv tests; Perl not available'
> -	test_done
> -fi
> -
>  find_diff() {
>  	sed '1,/^index /d' | sed '/^-- $/,$d'
>  }
> @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
>  +1
>  EOF
>
> -cat >hexdump <<'EOF'
> -#!/bin/sh
> -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> -EOF
> -chmod +x hexdump
> -
>  test_expect_success 'setup binary file with history' '
> +	write_script hexdump <<-\EOF &&
> +	tr "\000\001" "01" <"$1"
> +	EOF

So here the `hexdump` script is written, basically replacing NUL and SOH
with the digits zero and one, respectively. I wonder why the script does
not call `test-tool hexdump` instead? And I wonder even more why no test
case has to be adapted below this change in the same file. I _guess_ that
the reason is that the file named, creatively, "file" is initialized with
a NUL and a newline, committed, then a line is appended that contains SOH
and a newline, and then the test cases verify the hunk _headers_ only?

If using `test-tool hexdump <"$1"` would work here, too, I'd actually have
preferred that over the `tr` invocation, even if would still not be
recapitulating the functionality of that Perl script (which, contrary to
its name, seemed never to have output hexadecimal values...).

To be clear: I do not suggest to change the patch, I am merely puzzled why
the more obvious `test-tool hexdump <"$1"` was not used here?

>  	test_commit --printf one file "\\0\\n" &&
>  	test_commit --printf --append two file "\\01\\n"
>  '
> diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
> index cbe50b15772..15e012ccc7c 100755
> --- a/t/t4031-diff-rewrite-binary.sh
> +++ b/t/t4031-diff-rewrite-binary.sh
> @@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
>  	grep " rewrite file" diff
>  '
>
> -{
> -	echo "#!$SHELL_PATH"
> -	cat <<'EOF'
> -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> -EOF
> -} >dump
> -chmod +x dump
> -
>  test_expect_success 'setup textconv' '
> +	write_script dump <<-\EOF &&
> +	test-tool hexdump <"$1"
> +	EOF

So this looks much more like what I would have expected also in t4030,
and...

>  	echo file diff=foo >.gitattributes &&
>  	git config diff.foo.textconv "\"$(pwd)\""/dump
>  '
>
> -test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
> +test_expect_success 'rewrite diff respects textconv' '
>  	git diff -B >diff &&
> -	grep "dissimilarity index" diff &&
> -	grep "^-61" diff &&
> -	grep "^-0" diff
> +	test_grep "dissimilarity index" diff &&
> +	test_grep "^-3d 0a 00" diff &&
> +	test_grep "^+3d 0a 01" diff
>  '

... the adjustment of the expectations is actually going above and beyond,
the original test was not half as stringent as the new test is.

The rest of the patch looks good to me.

Ciao,
Johannes

>
>  test_done
> diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
> index b2730d200c8..3bd91da9707 100755
> --- a/t/t7815-grep-binary.sh
> +++ b/t/t7815-grep-binary.sh
> @@ -4,12 +4,6 @@ test_description='git grep in binary files'
>
>  . ./test-lib.sh
>
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping grep binary tests; Perl not available'
> -	test_done
> -fi
> -
>  test_expect_success 'setup' "
>  	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
>  	git add a &&
> @@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
>  	test_cmp expect actual
>  '
>
> -cat >nul_to_q_textconv <<'EOF'
> -#!/bin/sh
> -"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
> -EOF
> -chmod +x nul_to_q_textconv
> -
>  test_expect_success 'setup textconv filters' '
> +	write_script nul_to_q_textconv <<-\EOF &&
> +	tr "\000" "Q" <"$1"
> +	EOF
>  	echo a diff=foo >.gitattributes &&
>  	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
>  '
>
> --
> 2.49.0.472.ge94155a9ec.dirty
>
>

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-03-27 10:37   ` [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
@ 2025-04-01 18:56     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 18:56 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood


Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
> stdin. Refactor it to instead use awk(1) so that we drop the
> PERL_TEST_HELPERS prerequisite in users of this library.

It's my fault that this commit message is no longer correct because I
talked you into using `sed` instead...

Sorry,
Johannes

>
> Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
> now that the test suite doesn't bail out early anymore in case the
> prerequisite isn't set.
>
> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  t/lib-gpg.sh            |  6 +-----
>  t/t6300-for-each-ref.sh | 21 ++++++++++-----------
>  2 files changed, 11 insertions(+), 16 deletions(-)
>
> diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
> index 3845b6ac449..937b876bd05 100644
> --- a/t/lib-gpg.sh
> +++ b/t/lib-gpg.sh
> @@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '
>  '
>
>  sanitize_pgp() {
> -	perl -ne '
> -		/^-----END PGP/ and $in_pgp = 0;
> -		print unless $in_pgp;
> -		/^-----BEGIN PGP/ and $in_pgp = 1;
> -	'
> +	sed "/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}"
>  }
> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
> index 732a4d3171e..5db7038c417 100755
> --- a/t/t6300-for-each-ref.sh
> +++ b/t/t6300-for-each-ref.sh
> @@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
>  . "$TEST_DIRECTORY"/lib-gpg.sh
>  . "$TEST_DIRECTORY"/lib-terminal.sh
>
> -if ! test_have_prereq PERL_TEST_HELPERS
> -then
> -	skip_all='skipping for-each-ref tests; Perl not available'
> -	test_done
> -fi
> -
>  # Mon Jul 3 23:18:43 2006 +0000
>  datestamp=1151968723
>  setdate_and_increment () {
> @@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '
>  	test_must_fail git for-each-ref --format="%(raw)" --tcl
>  '
>
> -test_expect_success '%(raw) with --perl' '
> +test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
>  	git for-each-ref --format="\$name= %(raw);
>  print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
>  	cmp blob1 actual &&
> @@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '
>  '
>
>  test_trailer_option () {
> +	if test "$#" -eq 3
> +	then
> +		prereq="$1"
> +		shift
> +	fi &&
>  	title=$1 option=$2
>  	cat >expect
> -	test_expect_success "$title" '
> +	test_expect_success $prereq "$title" '
>  		git for-each-ref --format="%($option)" refs/heads/main >actual &&
>  		test_cmp expect actual &&
>  		git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
> @@ -1452,7 +1451,7 @@ test_trailer_option () {
>  	'
>  }
>
> -test_trailer_option '%(trailers:unfold) unfolds trailers' \
> +test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
>  	'trailers:unfold' <<-EOF
>  	$(unfold <trailers)
>
> @@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \
>
>  	EOF
>
> -test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
> +test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
>  	'trailers:only,unfold' <<-EOF
>  	$(grep -v patch.description <trailers | unfold)
>
>  	EOF
>
> -test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
> +test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
>  	'trailers:unfold,only' <<-EOF
>  	$(grep -v patch.description <trailers | unfold)
>
>
> --
> 2.49.0.472.ge94155a9ec.dirty
>
>

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-03-27 10:37   ` [PATCH v3 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
@ 2025-04-01 19:04     ` Johannes Schindelin
  2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-01 19:04 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> The `generate_random_characters()` helper function generates N
> random characters in the range 'a-z' and writes them into a file. The
> logic currently uses Perl, but it can be adapted rather easily by:
>
>   - Making `test-tool genrandom` generate an infinite stream.
>
>   - Using `tr -dc` to strip all characters which aren't in the range of
>     'a-z'.
>
>   - Using `test_copy_bytes()` to copy the first N bytes.

It would be conceptually more elegant to teach `genrandom` to optionally
output only lower-case letters. But that would be admittedly result in a
larger patch, therefore I am okay with keeping the patch as-is.

Ciao,
Johannes

>
> This allows us to drop the PERL_TEST_HELPERS prerequisite.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  t/t0021-conversion.sh | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
> index 4a892a91780..bf10d253ec4 100755
> --- a/t/t0021-conversion.sh
> +++ b/t/t0021-conversion.sh
> @@ -20,8 +20,7 @@ EOF
>  generate_random_characters () {
>  	LEN=$1
>  	NAME=$2
> -	test-tool genrandom some-seed $LEN |
> -		perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
> +	test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME"
>  }
>
>  filter_git () {
> @@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
>  	)
>  '
>
> -test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
> +test_expect_success 'required process filter should process multiple packets' '
>  	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
>  	test_config_global filter.protocol.required true &&
>
> @@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu
>  	)
>  '
>
> -test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
> +test_expect_success 'required process filter with clean error should fail' '
>  	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
>  	test_config_global filter.protocol.required true &&
>  	rm -rf repo &&
>
> --
> 2.49.0.472.ge94155a9ec.dirty
>
>

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 12/20] t: refactor tests depending on Perl to print data
  2025-04-01 18:35     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 08:35:25PM +0200, Johannes Schindelin wrote:
> Hi Patrick,
> 
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> 
> > A bunch of tests rely on Perl to print data in various different ways.
> > These usages fall into the following categories:
> >
> >   - Print data conditionally by matching patterns. These usecases can be
> >     converted to use awk(1) rather easily.
> >
> >   - Print data repeatedly. These usecases can typically be converted to
> >     use a combination of `test-tool genzeros` and sed(1).
> 
> It might be even more elegant to teach `genzeros` to generate streams of
> bytes other than NUL.

Agreed, that would feel more elegant indeed (well, despite the name
being inaccurate now). I decided against doing this so that we don't
have to introduce too many tools, but wouldn't mind doing so if you or
other people feel strongly about it.

> >   - Print data in reverse. These usecases can be converted to use
> >     awk(1).
> 
> Or, in one case, `sort -r`.

True, fixed.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-04-01 19:04     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 09:04:44PM +0200, Johannes Schindelin wrote:
> Hi Patrick,
> 
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> 
> > The `generate_random_characters()` helper function generates N
> > random characters in the range 'a-z' and writes them into a file. The
> > logic currently uses Perl, but it can be adapted rather easily by:
> >
> >   - Making `test-tool genrandom` generate an infinite stream.
> >
> >   - Using `tr -dc` to strip all characters which aren't in the range of
> >     'a-z'.
> >
> >   - Using `test_copy_bytes()` to copy the first N bytes.
> 
> It would be conceptually more elegant to teach `genrandom` to optionally
> output only lower-case letters. But that would be admittedly result in a
> larger patch, therefore I am okay with keeping the patch as-is.

Yeah, it's basically the same reason why I decided against teaching
`test-tool genzeros` to output arbitrary characters. And again, I'm
happy to adapt if anybody feels strongly, but meanwhile I'm being
pragmatic and go with the simple solution.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-04-01 18:26     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  2025-04-02 19:10         ` Johannes Schindelin
  0 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> 
> > In the early days of Git, Perl was used quite prominently throughout the
> > project. This has changed significantly as almost all of the executables
> > we ship nowadays have eventually been rewritten in C. Only a handful of
> > subsystems remain that require Perl:
> >
> >   - gitweb, a read-only web interface.
> >
> >   - A couple of scripts that allow importing repositories from GNU Arch,
> >     CVS and Subversion.
> >
> >   - git-send-email(1), which can be used to send mails.
> 
> There is also `git request-pull` which is a _shell_ script that runs
> `perl` to parse the output of `ls-remote`, and there is `git
> filter-branch` (which was apparently not yet dropped?) that uses Perl if
> the `--state-branch` option is in use.

Ah, indeed, thanks!

I should probably mark both of these to require Perl in our build
systems so that we have a source of truth what requires Perl and what
doesn't. git-filter-branch(1) also looks somewhat broken because it uses
Perl directly instead of using PERL_PATH.

On the other hand, maybe the better fix would be to just convert tools
to not use Perl at all anymore so that we can eventually get rid of this
dependency altogether. It feels like we're quite close, and many of
these conversions are low-hanging fruit.

> The patch looks good, in particular when fetching the `b4/pks-t-perlless`
> branch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f
> manually, as it is a rather large patch that is pretty much unreviewable
> on a mailing list.
> 
> Using several write-only `sed` invocations, I identified that there are
> only three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`
> prereq nor adding a test preamble of this form:
> 
> 	if ! test_have_prereq PERL_TEST_HELPERS
> 	then
> 		skip_all='skipping <something>; Perl not available'
> 		test_done
> 	fi

Thanks for double checking!

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator
  2025-04-01 18:32     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 08:32:02PM +0200, Johannes Schindelin wrote:
> Hi Patrick,
> 
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> 
> > We have a bunch of tests that use Perl to perform substitution via the
> > "s/" operator. These usecases can be trivially replaced with sed(1).
> 
> ... and sometimes `tr`.
> 
> In fact, it looks like...
> 
> > diff --git a/t/t7508-status.sh b/t/t7508-status.sh
> > index 14c41b2cb7c..cdc1d6fcc78 100755
> > --- a/t/t7508-status.sh
> > +++ b/t/t7508-status.sh
> > @@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
> >  	test_cmp expect output
> >  '
> >
> > -test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
> > +test_expect_success 'status -z implies porcelain' '
> >  	git status --porcelain |
> > -	perl -pe "s/\012/\000/g" >expect &&
> > +	tr "\012" "\000" >expect &&
> >  	git status -z >output &&
> >  	test_cmp expect output
> >  '
> 
> ... this change is not about `sed` at all, but only about `tr`.
> _Technically_, this hunk would therefore feel more at home in the previous
> patch. But practically, I actually do not mind it being here at all.

Yeah, the boundaries between commits are fuzzy at times. I mostly wanted
to split up similar changes so that the review load is somewhat
reasonable and not have a single patch that does it all at once. And
this site here did use Perl's substitution operator, so it's not wrong
per se that we do the conversion as part of this patch. But it's of
course wrong that I only mention sed(1) in the commit message.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-04-01 18:56     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 08:56:41PM +0200, Johannes Schindelin wrote:
> 
> Hi Patrick,
> 
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> 
> > The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
> > stdin. Refactor it to instead use awk(1) so that we drop the
> > PERL_TEST_HELPERS prerequisite in users of this library.
> 
> It's my fault that this commit message is no longer correct because I
> talked you into using `sed` instead...
> 
> Sorry,
> Johannes

No need to be sorry, should've catched that myself :) Thanks for the
suggestion in the first place, it made the new logic quite a bit easier
to read!

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-04-01 18:55     ` Johannes Schindelin
@ 2025-04-02  7:16       ` Patrick Steinhardt
  2025-04-02 19:17         ` Johannes Schindelin
  0 siblings, 1 reply; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-02  7:16 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

On Tue, Apr 01, 2025 at 08:55:22PM +0200, Johannes Schindelin wrote:
> On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> > diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
> > index c7d8eb12453..f904fc19f69 100755
> > --- a/t/t4030-diff-textconv.sh
> > +++ b/t/t4030-diff-textconv.sh
> > @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
> >  +1
> >  EOF
> >
> > -cat >hexdump <<'EOF'
> > -#!/bin/sh
> > -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> > -EOF
> > -chmod +x hexdump
> > -
> >  test_expect_success 'setup binary file with history' '
> > +	write_script hexdump <<-\EOF &&
> > +	tr "\000\001" "01" <"$1"
> > +	EOF
> 
> So here the `hexdump` script is written, basically replacing NUL and SOH
> with the digits zero and one, respectively. I wonder why the script does
> not call `test-tool hexdump` instead? And I wonder even more why no test
> case has to be adapted below this change in the same file. I _guess_ that
> the reason is that the file named, creatively, "file" is initialized with
> a NUL and a newline, committed, then a line is appended that contains SOH
> and a newline, and then the test cases verify the hunk _headers_ only?
> 
> If using `test-tool hexdump <"$1"` would work here, too, I'd actually have
> preferred that over the `tr` invocation, even if would still not be
> recapitulating the functionality of that Perl script (which, contrary to
> its name, seemed never to have output hexadecimal values...).
> 
> To be clear: I do not suggest to change the patch, I am merely puzzled why
> the more obvious `test-tool hexdump <"$1"` was not used here?

Phillip had the same comment, and I was trying to address that by
improving the commit message a bit. But seems like it still isn't clear
enough.

The reason why I decided against using `test-tool hexdump` is that it
would have a ripple effect. The output generated by that helper is not
the same as the output generated by the Perl script, so if we started to
use the hexdump helper I would have to adapt a bunch of tests in this
test file to update their expectations.

The result would look something like the appended patch, which I think
is quite awkward. On the one hand we have trailing whitespace in the
expectation, on the other hand we have weird seemingly-unrelated changes
in other tests. So I shied away from that and instead decided to use a
simpler variant of the textconv script.

Let me adapt the commit message once again and make it a bit more
concrete compared to the current fuzzy description.

Patrick

diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index f904fc19f69..16d7fd4c5ca 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -15,14 +15,14 @@ EOF
 cat >expect.text <<'EOF'
 --- a/file
 +++ b/file
-@@ -1 +1,2 @@
- 0
-+1
+@@ -1 +1 @@
+-00 0a 
++00 0a 01 0a 
 EOF
 
 test_expect_success 'setup binary file with history' '
 	write_script hexdump <<-\EOF &&
-	tr "\000\001" "01" <"$1"
+	test-tool hexdump <"$1"
 	EOF
 	test_commit --printf one file "\\0\\n" &&
 	test_commit --printf --append two file "\\01\\n"
@@ -92,7 +92,7 @@ test_expect_success 'show blob produces binary' '
 
 test_expect_success 'show --textconv blob produces text' '
 	git show --textconv HEAD:file >actual &&
-	printf "0\\n1\\n" >expect &&
+	printf "00 0a 01 0a \n" >expect &&
 	test_cmp expect actual
 '
 
@@ -103,7 +103,7 @@ test_expect_success 'show --no-textconv blob produces binary' '
 '
 
 test_expect_success 'grep-diff (-G) operates on textconv data (add)' '
-	echo one >expect &&
+	printf "two\none\n" >expect &&
 	git log --root --format=%s -G0 >actual &&
 	test_cmp expect actual
 '
@@ -115,7 +115,7 @@ test_expect_success 'grep-diff (-G) operates on textconv data (modification)' '
 '
 
 test_expect_success 'pickaxe (-S) operates on textconv data (add)' '
-	echo one >expect &&
+	printf "two\none\n" >expect &&
 	git log --root --format=%s -S0 >actual &&
 	test_cmp expect actual
 '
@@ -146,9 +146,8 @@ symlink=$(git rev-parse --short $(printf frotz | git hash-object --stdin))
 cat >expect.typechange <<EOF
 --- a/file
 +++ /dev/null
-@@ -1,2 +0,0 @@
--0
--1
+@@ -1 +0,0 @@
+-00 0a 01 0a 
 diff --git a/file b/file
 new file mode 120000
 index 0000000..$symlink

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-04-02  7:16       ` Patrick Steinhardt
@ 2025-04-02 19:10         ` Johannes Schindelin
  2025-04-03  5:05           ` Patrick Steinhardt
  0 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-02 19:10 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Wed, 2 Apr 2025, Patrick Steinhardt wrote:

> On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:
> > On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> >
> > > In the early days of Git, Perl was used quite prominently throughout
> > > the project. This has changed significantly as almost all of the
> > > executables we ship nowadays have eventually been rewritten in C.
> > > Only a handful of subsystems remain that require Perl:
> > >
> > >   - gitweb, a read-only web interface.
> > >
> > >   - A couple of scripts that allow importing repositories from GNU Arch,
> > >     CVS and Subversion.
> > >
> > >   - git-send-email(1), which can be used to send mails.
> >
> > There is also `git request-pull` which is a _shell_ script that runs
> > `perl` to parse the output of `ls-remote`, and there is `git
> > filter-branch` (which was apparently not yet dropped?) that uses Perl if
> > the `--state-branch` option is in use.
>
> Ah, indeed, thanks!
>
> I should probably mark both of these to require Perl in our build
> systems so that we have a source of truth what requires Perl and what
> doesn't. git-filter-branch(1) also looks somewhat broken because it uses
> Perl directly instead of using PERL_PATH.

True.

> On the other hand, maybe the better fix would be to just convert tools
> to not use Perl at all anymore so that we can eventually get rid of this
> dependency altogether. It feels like we're quite close, and many of
> these conversions are low-hanging fruit.

As for `git filter-branch`, we could simply -- what were the wise words of
Elijah's mentor? -- "debug" it. I.e. delete it and be happy about it.

> > The patch looks good, in particular when fetching the `b4/pks-t-perlless`
> > branch from https://gitlab.com/gitlab-org/git and inspecting 8fc639f99d9f
> > manually, as it is a rather large patch that is pretty much unreviewable
> > on a mailing list.
> >
> > Using several write-only `sed` invocations, I identified that there are
> > only three hunks that are neither adding a stand-alone `PERL_TEST_HELPERS`
> > prereq nor adding a test preamble of this form:
> >
> > 	if ! test_have_prereq PERL_TEST_HELPERS
> > 	then
> > 		skip_all='skipping <something>; Perl not available'
> > 		test_done
> > 	fi
>
> Thanks for double checking!

You're welcome. I am a bit embarrassed to admit that it took me quite a
bit of time, I believe it was around an hour, to validate this patch
alone.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-04-02  7:16       ` Patrick Steinhardt
@ 2025-04-02 19:17         ` Johannes Schindelin
  0 siblings, 0 replies; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-02 19:17 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Wed, 2 Apr 2025, Patrick Steinhardt wrote:

> On Tue, Apr 01, 2025 at 08:55:22PM +0200, Johannes Schindelin wrote:
> > On Thu, 27 Mar 2025, Patrick Steinhardt wrote:
> > > diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
> > > index c7d8eb12453..f904fc19f69 100755
> > > --- a/t/t4030-diff-textconv.sh
> > > +++ b/t/t4030-diff-textconv.sh
> > > @@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
> > >  +1
> > >  EOF
> > >
> > > -cat >hexdump <<'EOF'
> > > -#!/bin/sh
> > > -"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
> > > -EOF
> > > -chmod +x hexdump
> > > -
> > >  test_expect_success 'setup binary file with history' '
> > > +	write_script hexdump <<-\EOF &&
> > > +	tr "\000\001" "01" <"$1"
> > > +	EOF
> >
> > So here the `hexdump` script is written, basically replacing NUL and SOH
> > with the digits zero and one, respectively. I wonder why the script does
> > not call `test-tool hexdump` instead? And I wonder even more why no test
> > case has to be adapted below this change in the same file. I _guess_ that
> > the reason is that the file named, creatively, "file" is initialized with
> > a NUL and a newline, committed, then a line is appended that contains SOH
> > and a newline, and then the test cases verify the hunk _headers_ only?
> >
> > If using `test-tool hexdump <"$1"` would work here, too, I'd actually have
> > preferred that over the `tr` invocation, even if would still not be
> > recapitulating the functionality of that Perl script (which, contrary to
> > its name, seemed never to have output hexadecimal values...).
> >
> > To be clear: I do not suggest to change the patch, I am merely puzzled why
> > the more obvious `test-tool hexdump <"$1"` was not used here?
>
> Phillip had the same comment, and I was trying to address that by
> improving the commit message a bit. But seems like it still isn't clear
> enough.

Or I am too slow, that's also a possibility.

> The reason why I decided against using `test-tool hexdump` is that it
> would have a ripple effect. The output generated by that helper is not
> the same as the output generated by the Perl script, so if we started to
> use the hexdump helper I would have to adapt a bunch of tests in this
> test file to update their expectations.
>
> The result would look something like the appended patch, which I think
> is quite awkward. On the one hand we have trailing whitespace in the
> expectation, on the other hand we have weird seemingly-unrelated changes
> in other tests. So I shied away from that and instead decided to use a
> simpler variant of the textconv script.

That makes sense. Not only would it be a chattier diff, it would be even
harder to validate. I would probably have written an entire paragraph in the
commit message just about this decision, if only to get frustration about
the state of Git's tests off of my chest. Your decision to avoid spending
more energy on this than you already did sounds like a smart one to me,
and I am sorry that I forced you to explain this one more time.

> Let me adapt the commit message once again and make it a bit more
> concrete compared to the current fuzzy description.

Your explanation is sufficient for me, therefore you do not need to send
another iteration merely for my sake.

Thank you,
Johannes


^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                     ` (20 preceding siblings ...)
  2025-03-28 10:29   ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Phillip Wood
@ 2025-04-02 19:32   ` Johannes Schindelin
  21 siblings, 0 replies; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-02 19:32 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 27 Mar 2025, Patrick Steinhardt wrote:

> while Git was initially building on Perl quite a lot, the significance
> of Perl has been dwindling over the years as more and more functionality
> was converted into C builtins. Nowadays, an installation with Perl-based
> features disabled is almost fully functional, only a handful of features
> remain that require Perl:
>
>   - gitweb, a read-only web interface.
>
>   - A couple of scripts that allow importing repositories from GNU Arch,
>     CVS and Subversion.
>
>   - git-send-email(1), which can be used to send mails.
>
>   - Our Perl bindings for Git.
>
>   - The netrc Git credential helper.
>
> None of these features really are critical for day-to-day usage of Git,
> and most users probably wouldn't even notice if those features were not
> installed. Perl is thus very much optional nowadays.
>
> There is one big exception though: it is impossible to run our test
> suite without a Perl interpreter, so it is not easily possible to verify
> that a Perl-less installation actually works as expected. For most of
> the part though our test suite doesn't use all that much Perl, either.
> It is present in a couple of critical paths, but those are easy to adapt
> to not use Perl anymore.
>
> This is exactly what this patch series does: it refactors a couple of
> central parts in our test suite to not use Perl anymore so that it
> becomes possible to run most of our tests entirely without Perl. Tests
> that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq
> so that they only execute when a Perl interpreter is available.
>
> With this patch series, 30342 out of 31358 tests pass, which is around
> 97% of our tests.

Thank you so much for working on this. I finally finished my review, I
simply ran out of time yesterday. The patches look good to me, and the
result even more so.

From my perspective, it also sure looks like good timing, even so much as
two years ago it would probably not have been realistically achievable to
drop Git's test suite's dependency on Perl.

On Git for Windows' side, I have opened a ticket [*1*] that even discusses
the idea of dropping Perl from Git for Windows' installer altogether. The
appeal of this is that Perl is quite a hefty dependency with all of those
Perl modules that are part of the set that Perl users simply expect to be
present. I did not investigate this fully yet, but would expect a
reduction of at least 10MB, and Git for Windows carries this essentially
for `git svn` and little else.

So yes, I am quite happy about this direction, and could also imagine that
at least the Windows test jobs (which use `prove` like the rest of the
tests in Git's CI builds) could potentially switch away from `prove` to
`test-tool run-command testsuite` and then drop Perl from the
`git-sdk-x86_64-minimal` artifact that needs to be downloaded and
installed for every single Windows job of Git's CI. (The `test-tool` may
need to learn a few more tricks, but I'd be surprised if any non-trivial
patches were needed there to essentially replace `prove` as far as Git's
needs are concerned.)

Ciao,
Johannes

Footnote *1*: https://github.com/git-for-windows/git/issues/5393

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-04-02 19:10         ` Johannes Schindelin
@ 2025-04-03  5:05           ` Patrick Steinhardt
  0 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood, Elijah Newren

On Wed, Apr 02, 2025 at 09:10:16PM +0200, Johannes Schindelin wrote:
> On Wed, 2 Apr 2025, Patrick Steinhardt wrote:
> > On Tue, Apr 01, 2025 at 08:26:36PM +0200, Johannes Schindelin wrote:
> > On the other hand, maybe the better fix would be to just convert tools
> > to not use Perl at all anymore so that we can eventually get rid of this
> > dependency altogether. It feels like we're quite close, and many of
> > these conversions are low-hanging fruit.
> 
> As for `git filter-branch`, we could simply -- what were the wise words of
> Elijah's mentor? -- "debug" it. I.e. delete it and be happy about it.

I wouldn't mind it, but we should probably have a proper replacement for
it first. Ideally in the form of git-filter-repo(1) being part of Git
itself.

In any case, meanwhile I have created a follow-up patch series that
adapts both git-filter-branch(1) and git-request-pull(1) to not require
Perl anymore.

Patrick

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite
  2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
                   ` (21 preceding siblings ...)
  2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
@ 2025-04-03  5:05 ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
                     ` (20 more replies)
  22 siblings, 21 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi,

while Git was initially building on Perl quite a lot, the significance
of Perl has been dwindling over the years as more and more functionality
was converted into C builtins. Nowadays, an installation with Perl-based
features disabled is almost fully functional, only a handful of features
remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these features really are critical for day-to-day usage of Git,
and most users probably wouldn't even notice if those features were not
installed. Perl is thus very much optional nowadays.

There is one big exception though: it is impossible to run our test
suite without a Perl interpreter, so it is not easily possible to verify
that a Perl-less installation actually works as expected. For most of
the part though our test suite doesn't use all that much Perl, either.
It is present in a couple of critical paths, but those are easy to adapt
to not use Perl anymore.

This is exactly what this patch series does: it refactors a couple of
central parts in our test suite to not use Perl anymore so that it
becomes possible to run most of our tests entirely without Perl. Tests
that still depend on Perl are marked with a new PERL_TEST_HELPERS prereq
so that they only execute when a Perl interpreter is available.

With this patch series, 30342 out of 31358 tests pass, which is around
97% of our tests.

Changes in v2:
  - Improve a couple of conversions based on feedback.
  - Clarify the commit message of the textconv conversion.
  - Fix a copy-paste error when it comes to skipping tests in t4103.
  - Link to v1: https://lore.kernel.org/r/20250320-b4-pks-t-perlless-v1-0-b1eefe27ac55@pks.im

Changes in v3:
  - Remove more useless indirections for sed(1).
  - Link to v2: https://lore.kernel.org/r/20250325-b4-pks-t-perlless-v2-0-4b87b8072670@pks.im

Changes in v4:
  - Improve a couple of commit messages to better explain the changes.
  - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (20):
      t: skip chain lint when PERL_PATH is unset
      t: refactor environment sanitization to not use Perl
      t: adapt character translation helpers to not use Perl
      t: adapt `test_copy_bytes()` to not use Perl
      t: adapt `test_readlink()` to not use Perl
      t: introduce PERL_TEST_HELPERS prerequisite
      t: adapt existing PERL prerequisites
      meson: stop requiring Perl when tests are enabled
      Makefile: stop requiring Perl when running tests
      t: refactor tests depending on Perl transliteration operator
      t: refactor tests depending on Perl substitution operator
      t: refactor tests depending on Perl to print data
      t: refactor tests depending on Perl for textconv scripts
      t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
      t/lib-t6000: refactor `name_from_description()` to not depend on Perl
      t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
      t0021: refactor `generate_random_characters()` to not depend on Perl
      t0210: refactor trace2 scrubbing to not use Perl
      t5316: refactor `max_chain()` to not depend on Perl
      t5703: refactor test to not depend on Perl

 meson.build                               |  2 +-
 t/Makefile                                | 16 +++++++--
 t/helper/test-path-utils.c                | 13 ++++++++
 t/helper/test-sha1.sh                     |  4 +--
 t/lib-diff.sh                             |  4 +--
 t/lib-gpg.sh                              |  6 +---
 t/lib-httpd.sh                            |  2 +-
 t/lib-httpd/apache.conf                   |  6 ++--
 t/lib-httpd/apply-one-time-perl.sh        | 27 ---------------
 t/lib-httpd/apply-one-time-script.sh      | 26 +++++++++++++++
 t/lib-t6000.sh                            | 13 ++++----
 t/t0008-ignores.sh                        |  4 +--
 t/t0021-conversion.sh                     | 13 ++++----
 t/t0090-cache-tree.sh                     |  4 +--
 t/t0210-trace2-normal.sh                  | 55 ++++++++++++++++++++++++-------
 t/t0210/scrub_normal.perl                 | 54 ------------------------------
 t/t0211-trace2-perf.sh                    |  6 ++++
 t/t0610-reftable-basics.sh                |  5 ++-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       | 16 +++++----
 t/t1007-hash-object.sh                    |  6 ++--
 t/t1010-mktree.sh                         |  4 +--
 t/t1450-fsck.sh                           |  6 ++--
 t/t3300-funny-names.sh                    |  6 ++--
 t/t4013-diff-various.sh                   |  6 ++++
 t/t4014-format-patch.sh                   | 30 ++++++++---------
 t/t4020-diff-external.sh                  |  2 +-
 t/t4029-diff-trailing-space.sh            |  3 +-
 t/t4030-diff-textconv.sh                  |  9 ++---
 t/t4031-diff-rewrite-binary.sh            | 17 ++++------
 t/t4058-diff-duplicates.sh                |  6 ++++
 t/t4103-apply-binary.sh                   |  6 ++--
 t/t4116-apply-reverse.sh                  |  4 +--
 t/t4150-am.sh                             |  8 ++---
 t/t4200-rerere.sh                         |  8 ++---
 t/t4205-log-pretty-formats.sh             |  6 ++--
 t/t4216-log-bloom.sh                      |  8 ++---
 t/t5004-archive-corner-cases.sh           |  6 ++++
 t/t5300-pack-object.sh                    | 10 +++---
 t/t5303-pack-corruption-resilience.sh     |  6 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               | 10 +++---
 t/t5318-commit-graph.sh                   | 12 +++----
 t/t5319-multi-pack-index.sh               | 16 ++++-----
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  4 +--
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           | 12 +++----
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  2 +-
 t/t5503-tagfollow.sh                      |  6 ++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++
 t/t5532-fetch-proxy.sh                    |  6 ++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  | 15 ++++-----
 t/t5551-http-fetch-smart.sh               |  7 ++++
 t/t5562-http-backend-content-length.sh    |  6 ++++
 t/t5601-clone.sh                          |  4 +--
 t/t5616-partial-clone.sh                  | 46 ++++++++++++++------------
 t/t5701-git-serve.sh                      |  5 ++-
 t/t5702-protocol-v2.sh                    | 21 +++++++-----
 t/t5703-upload-pack-ref-in-want.sh        | 29 ++++++++--------
 t/t5710-promisor-remote-capability.sh     |  6 ++++
 t/t6011-rev-list-with-bad-commit.sh       | 14 +++++---
 t/t6013-rev-list-reverse-parents.sh       | 10 +++---
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++
 t/t6115-rev-list-du.sh                    |  2 +-
 t/t6300-for-each-ref.sh                   | 15 ++++++---
 t/t7006-pager.sh                          |  6 ++--
 t/t7416-submodule-dash-url.sh             |  3 +-
 t/t7501-commit-basic-functionality.sh     |  6 ++--
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  9 ++---
 t/t8001-annotate.sh                       |  6 ++++
 t/t8002-blame.sh                          |  8 ++++-
 t/t8006-blame-textconv.sh                 |  2 +-
 t/t8011-blame-split-file.sh               |  6 ++--
 t/t8012-blame-colors.sh                   |  6 ++++
 t/t9137-git-svn-dcommit-clobber-series.sh | 10 +++---
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib-functions.sh                   | 20 +++--------
 t/test-lib.sh                             | 49 +++++++++++++++++----------
 84 files changed, 471 insertions(+), 373 deletions(-)

Range-diff versus v3:

 1:  9a500263cea =  1:  cd553f570b7 t: skip chain lint when PERL_PATH is unset
 2:  3cc409f35ab =  2:  bd2b95c2fa5 t: refactor environment sanitization to not use Perl
 3:  46bba778281 =  3:  81b99adaf5b t: adapt character translation helpers to not use Perl
 4:  72f65ee6f3d =  4:  ef624217370 t: adapt `test_copy_bytes()` to not use Perl
 5:  57b4e5e0b2c =  5:  4e6c4b654f5 t: adapt `test_readlink()` to not use Perl
 6:  61230a9f7e5 !  6:  cbefcec77f9 t: introduce PERL_TEST_HELPERS prerequisite
    @@ Commit message
     
           - git-send-email(1), which can be used to send mails.
     
    +      - git-request-pull(1), which is used to request somebody to pull from
    +        a URL by sending an email.
    +
    +      - git-filter-branch(1), which uses Perl with the `--state-branch`
    +        option. This command is typically recommended against nowadays in
    +        favor of git-filter-repo(1).
    +
           - Our Perl bindings for Git.
     
           - The netrc Git credential helper.
 7:  37a944f2295 =  7:  8d08fe26be3 t: adapt existing PERL prerequisites
 8:  58513ff9510 =  8:  c4451024f2d meson: stop requiring Perl when tests are enabled
 9:  68cdf732fe7 =  9:  2d3c3d10c00 Makefile: stop requiring Perl when running tests
10:  acba0e69f8f = 10:  25737787f61 t: refactor tests depending on Perl transliteration operator
11:  888b283db98 ! 11:  863e029c0d3 t: refactor tests depending on Perl substitution operator
    @@ Commit message
         t: refactor tests depending on Perl substitution operator
     
         We have a bunch of tests that use Perl to perform substitution via the
    -    "s/" operator. These usecases can be trivially replaced with sed(1).
    +    "s/" operator. These usecases can be trivially replaced with sed(1) and
    +    tr(1).
     
         Refactor the tests accordingly so that we can drop a couple of
         PERL_TEST_HELPERS prerequisites.
12:  e2fbbad39e3 ! 12:  ba13f633705 t: refactor tests depending on Perl to print data
    @@ Commit message
             use a combination of `test-tool genzeros` and sed(1).
     
           - Print data in reverse. These usecases can be converted to use
    -        awk(1).
    +        awk(1) or `sort -r`.
     
         Refactor the tests accordingly so that we can drop a couple of
         PERL_TEST_HELPERS prerequisites.
13:  12950479b79 ! 13:  80bda885e4d t: refactor tests depending on Perl for textconv scripts
    @@ Commit message
         Refactor these tests to instead be implemented via shell utilities so
         that we can drop a couple of PERL_TEST_HELPERS prerequisites.
     
    -    Note that not all of the conversions are a one-to-one equivalent to the
    -    previous textconv scripts. But that's not really needed in the first
    -    place: we only care that the textconv script does something, and that
    -    can be verified trivially without having a full-blown invocation of
    -    hexdump. So at times, the implementation of the textconv scripts is
    -    reduced to their bare minimum and the expectations of those tests are
    -    adapted accordingly.
    +    Note that the conversion in t4030 is not a one-to-one equivalent to the
    +    previous textconv script. Before this change we used to essentially do a
    +    hexdump via Perl. The obvious conversion here would be to use `test-tool
    +    hexdump` like we do for the other tests. But this would lead to a ripple
    +    effect where we would have to adapt a bunch of other tests with a bunch
    +    of seemingly unrelated changes, which would be somewhat awkward.
    +
    +    Instead, we're going with the minimum viable change: the test files we
    +    write contain "\001" and "\000", and the test's expectation is that
    +    those get translated into proper ASCII characters. So instead of doing a
    +    full hexdump, we simply use tr(1) to translate these specific bytes.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
14:  e3fe9e7292f ! 14:  da8e5e89029 t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
    @@ Commit message
         t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
     
         The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
    -    stdin. Refactor it to instead use awk(1) so that we drop the
    +    stdin. Refactor it to instead use sed(1) so that we drop the
         PERL_TEST_HELPERS prerequisite in users of this library.
     
         Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
15:  8c180723c5d = 15:  98afe2b4f71 t/lib-t6000: refactor `name_from_description()` to not depend on Perl
16:  9e5d5fc4d57 = 16:  a7d26d221cb t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
17:  4e5431788b0 = 17:  4b36ae2a602 t0021: refactor `generate_random_characters()` to not depend on Perl
18:  f7fd16661ca = 18:  27c720a3952 t0210: refactor trace2 scrubbing to not use Perl
19:  ee8d1bed611 = 19:  e08ed2f2c64 t5316: refactor `max_chain()` to not depend on Perl
20:  740009a2d0c = 20:  710158c13a7 t5703: refactor test to not depend on Perl

---
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
change-id: 20250317-b4-pks-t-perlless-138cf94696b8


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
                     ` (19 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our chainlint script verifies that test files have proper '&&' chains.
This script is written in Perl and executed for every test file before
executing the test logic itself.

In subsequent commits we're about to refactor our test suite so that
Perl becomes an optional dependency, only. And while it is already
possible to disable this linter, developers that don't have Perl
available at all would always have to disable the linter manually, which
is rather cumbersome.

Disable the chain linter automatically in case PERL_PATH isn't set to
make this a bit less annoying. Bail out with an error in case the
developer has asked explicitly for the chain linter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9001ed3a647..1ce3b32fcac 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1523,6 +1523,22 @@ then
 	export LSAN_OPTIONS
 fi
 
+if test -z "$PERL_PATH"
+then
+	case "${GIT_TEST_CHAIN_LINT:-unset}" in
+	unset)
+		GIT_TEST_CHAIN_LINT=0
+		;;
+	0)
+		# The user has explicitly disabled the chain linter, so we
+		# don't have anything to worry about.
+		;;
+	*)
+		BAIL_OUT 'You need Perl for the chain linter'
+		;;
+	esac
+fi
+
 if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 &&
    test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 02/20] t: refactor environment sanitization to not use Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 03/20] t: adapt character translation helpers " Patrick Steinhardt
                     ` (18 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Before executing tests we first sanitize the environment. Part of the
sanitization is to unset a couple of environment variables that we know
will change the behaviour of Git. This is done with a small Perl script,
which has the consequence that having a Perl interpreter available is a
strict requirement for running our unit tests.

The logic itself isn't particularly involved: we simply unset every
environment variable whose key starts with 'GIT_', but then explicitly
allow a subset of these.

Refactor the logic to instead use sed(1) so that it becomes possible to
execute our tests without Perl.

Based-on-patch-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib.sh | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1ce3b32fcac..a62699d6c79 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -499,24 +499,20 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e '
-	my @env = keys %ENV;
-	my $ok = join("|", qw(
-		TRACE
-		DEBUG
-		TEST
-		.*_TEST
-		PROVE
-		VALGRIND
-		UNZIP
-		PERF_
-		CURL_VERBOSE
-		TRACE_CURL
-		BUILD_DIR
-	));
-	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
-	print join("\n", @vars);
-')
+unset VISUAL EMAIL LANGUAGE $(env | sed -n \
+	-e '/^GIT_TRACE/d' \
+	-e '/^GIT_DEBUG/d' \
+	-e '/^GIT_TEST/d' \
+	-e '/^GIT_.*_TEST/d' \
+	-e '/^GIT_PROVE/d' \
+	-e '/^GIT_VALGRIND/d' \
+	-e '/^GIT_UNZIP/d' \
+	-e '/^GIT_PERF_/d' \
+	-e '/^GIT_CURL_VERBOSE/d' \
+	-e '/^GIT_TRACE_CURL/d' \
+	-e '/^GIT_BUILD_DIR/d' \
+	-e 's/^\(GIT_[^=]*\)=.*/\1/p'
+)
 unset XDG_CACHE_HOME
 unset XDG_CONFIG_HOME
 unset GITPERLLIB

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 03/20] t: adapt character translation helpers to not use Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
                     ` (17 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of helper functions that translate characters, e.g.
from LF to NUL or NUL to 'Q' and vice versa. These helpers use Perl
scripts, but they can be trivially adapted to instead use tr(1).

Note that one specialty here is the handling of NUL characters in tr(1),
which historically wasn't implemented correctly on all platforms. But
quoting tr(1p):

    It was considered that automatically stripping NUL characters from
    the input was not correct functionality.  However, the removal of -n
    in a later proposal does not remove the requirement that tr
    correctly process NUL characters in its input stream.

So when tr(1) is implemented following the POSIX standard then it is
expected to handle the transliteration of NUL just fine.

Refactor the helpers accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 79377bc0fc2..377f08a1428 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -88,15 +88,15 @@ test_decode_color () {
 }
 
 lf_to_nul () {
-	perl -pe 'y/\012/\000/'
+	tr '\012' '\000'
 }
 
 nul_to_q () {
-	perl -pe 'y/\000/Q/'
+	tr '\000' 'Q'
 }
 
 q_to_nul () {
-	perl -pe 'y/Q/\000/'
+	tr 'Q' '\000'
 }
 
 q_to_cr () {

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 04/20] t: adapt `test_copy_bytes()` to not use Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 03/20] t: adapt character translation helpers " Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
                     ` (16 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_copy_bytes()` helper function copies up to N bytes from stdin
to stdout. This is implemented using Perl, but it can be trivially
adapted to instead use dd(1).

Refactor the helper accordingly, which allows a bunch of tests to pass
when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/test-lib-functions.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 377f08a1428..c4b4d3a4c7f 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1640,17 +1640,7 @@ test_match_signal () {
 
 # Read up to "$1" bytes (or to EOF) from stdin and write them to stdout.
 test_copy_bytes () {
-	perl -e '
-		my $len = $ARGV[1];
-		while ($len > 0) {
-			my $s;
-			my $nread = sysread(STDIN, $s, $len);
-			die "cannot read: $!" unless defined($nread);
-			last unless $nread;
-			print $s;
-			$len -= $nread;
-		}
-	' - "$1"
+	dd ibs=1 count="$1" 2>/dev/null
 }
 
 # run "$@" inside a non-git directory

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 05/20] t: adapt `test_readlink()` to not use Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (3 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
                     ` (15 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `test_readlink()` helper function reads a symbolic link and returns
the path it is pointing to. It is thus equivalent to the readlink(1)
utility, which isn't available on all supported platforms. As such, it
is implemented using Perl so that we can use it even on platforms where
the shell utility isn't available.

While using readlink(1) is not an option, what we can do is to implement
the logic ourselves in our test-tool. Do so, which allows a bunch of
tests to pass when Perl is not available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-path-utils.c | 13 +++++++++++++
 t/test-lib-functions.sh    |  2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 72ac8d1b1b0..54d9ba98c0e 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -323,6 +323,19 @@ int cmd__path_utils(int argc, const char **argv)
 		return 0;
 	}
 
+	if (argc >= 2 && !strcmp(argv[1], "readlink")) {
+		struct strbuf target = STRBUF_INIT;
+		while (argc > 2) {
+			if (strbuf_readlink(&target, argv[2], 0) < 0)
+				die_errno("cannot read link at '%s'", argv[2]);
+			puts(target.buf);
+			argc--;
+			argv++;
+		}
+		strbuf_release(&target);
+		return 0;
+	}
+
 	if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
 		while (argc > 2) {
 			puts(absolute_path(argv[2]));
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c4b4d3a4c7f..bff8c4d1b41 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1979,7 +1979,7 @@ test_remote_https_urls() {
 # Print the destination of symlink(s) provided as arguments. Basically
 # the same as the readlink command, but it's not available everywhere.
 test_readlink () {
-	perl -le 'print readlink($_) for @ARGV' "$@"
+	test-tool path-utils readlink "$@"
 }
 
 # Set mtime to a fixed "magic" timestamp in mid February 2009, before we

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 06/20] t: introduce PERL_TEST_HELPERS prerequisite
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (4 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
                     ` (14 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

In the early days of Git, Perl was used quite prominently throughout the
project. This has changed significantly as almost all of the executables
we ship nowadays have eventually been rewritten in C. Only a handful of
subsystems remain that require Perl:

  - gitweb, a read-only web interface.

  - A couple of scripts that allow importing repositories from GNU Arch,
    CVS and Subversion.

  - git-send-email(1), which can be used to send mails.

  - git-request-pull(1), which is used to request somebody to pull from
    a URL by sending an email.

  - git-filter-branch(1), which uses Perl with the `--state-branch`
    option. This command is typically recommended against nowadays in
    favor of git-filter-repo(1).

  - Our Perl bindings for Git.

  - The netrc Git credential helper.

None of these subsystems can really be considered to be part of the
"core" of Git, and an installation without them is fully functional.
It is more likely than not that an end user wouldn't even notice that
any features are missing if those tools weren't installed. But while
Perl nowadays very much is an optional dependency of Git, there is a
significant limitation when Perl isn't available: developers cannot run
our test suite.

Preceding commits have started to lift this restriction by removing the
strict dependency on Perl in many central parts of the test library. But
there are still many tests that rely on small Perl helpers to do various
different things.

Introduce a new PERL_TEST_HELPERS prerequisite that guards all tests
that require Perl. This prerequisite is explicitly different than the
preexisting PERL prerequisite:

  - PERL records whether or not features depending on the Perl
    interpreter are built.

  - PERL_TEST_HELPERS records whether or not a Perl interpreter is
    available for our tests.

By having these two separate prerequisites we can thus distinguish
between tests that inherently depend on Perl because the underlying
feature does, and those tests that depend on Perl because the test
itself is using Perl.

Adapt all tests to set the PERL_TEST_HELPERS prerequisite as needed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        |  6 ++++++
 t/t0021-conversion.sh                     |  4 ++--
 t/t0210-trace2-normal.sh                  |  6 ++++++
 t/t0211-trace2-perf.sh                    |  6 ++++++
 t/t0610-reftable-basics.sh                |  2 +-
 t/t0613-reftable-write-options.sh         |  2 +-
 t/t1006-cat-file.sh                       |  2 +-
 t/t1007-hash-object.sh                    |  6 +++---
 t/t1010-mktree.sh                         |  4 ++--
 t/t1450-fsck.sh                           |  6 +++---
 t/t3300-funny-names.sh                    |  6 +++---
 t/t4013-diff-various.sh                   |  6 ++++++
 t/t4014-format-patch.sh                   | 30 +++++++++++++++---------------
 t/t4020-diff-external.sh                  |  4 ++--
 t/t4029-diff-trailing-space.sh            |  2 +-
 t/t4030-diff-textconv.sh                  |  6 ++++++
 t/t4031-diff-rewrite-binary.sh            |  2 +-
 t/t4058-diff-duplicates.sh                |  6 ++++++
 t/t4103-apply-binary.sh                   |  6 ++++++
 t/t4116-apply-reverse.sh                  |  6 ++++++
 t/t4150-am.sh                             |  2 +-
 t/t4200-rerere.sh                         |  6 ++++++
 t/t4205-log-pretty-formats.sh             |  6 +++---
 t/t4216-log-bloom.sh                      |  8 ++++----
 t/t5004-archive-corner-cases.sh           |  6 ++++++
 t/t5300-pack-object.sh                    |  6 ++++++
 t/t5303-pack-corruption-resilience.sh     |  4 ++--
 t/t5310-pack-bitmaps.sh                   |  2 +-
 t/t5316-pack-delta-depth.sh               |  8 ++++----
 t/t5318-commit-graph.sh                   | 12 ++++++------
 t/t5319-multi-pack-index.sh               | 16 ++++++++--------
 t/t5324-split-commit-graph.sh             |  2 +-
 t/t5326-multi-pack-bitmaps.sh             |  2 +-
 t/t5328-commit-graph-64bit-time.sh        |  2 +-
 t/t5333-pseudo-merge-bitmaps.sh           |  6 ++++++
 t/t5400-send-pack.sh                      |  2 +-
 t/t5410-receive-pack-alternates.sh        |  4 ++--
 t/t5503-tagfollow.sh                      |  6 ++++++
 t/t5504-fetch-receive-strict.sh           |  2 +-
 t/t5510-fetch.sh                          |  6 ++++++
 t/t5532-fetch-proxy.sh                    |  6 ++++++
 t/t5534-push-signed.sh                    |  2 +-
 t/t5537-fetch-shallow.sh                  |  2 +-
 t/t5551-http-fetch-smart.sh               |  7 +++++++
 t/t5562-http-backend-content-length.sh    |  6 ++++++
 t/t5601-clone.sh                          |  4 ++--
 t/t5616-partial-clone.sh                  |  6 +++---
 t/t5701-git-serve.sh                      |  2 +-
 t/t5702-protocol-v2.sh                    |  6 +++---
 t/t5703-upload-pack-ref-in-want.sh        |  6 ++++++
 t/t5710-promisor-remote-capability.sh     |  6 ++++++
 t/t6002-rev-list-bisect.sh                |  6 ++++++
 t/t6003-rev-list-topo-order.sh            |  6 ++++++
 t/t6011-rev-list-with-bad-commit.sh       |  6 ++++++
 t/t6013-rev-list-reverse-parents.sh       |  4 ++--
 t/t6102-rev-list-unexpected-objects.sh    |  6 ++++++
 t/t6115-rev-list-du.sh                    |  6 ++++++
 t/t6300-for-each-ref.sh                   |  6 ++++++
 t/t7006-pager.sh                          |  2 +-
 t/t7416-submodule-dash-url.sh             |  6 ++++++
 t/t7508-status.sh                         |  2 +-
 t/t7815-grep-binary.sh                    |  6 ++++++
 t/t8001-annotate.sh                       |  6 ++++++
 t/t8002-blame.sh                          |  6 ++++++
 t/t8006-blame-textconv.sh                 |  6 ++++++
 t/t8011-blame-split-file.sh               |  6 +++---
 t/t8012-blame-colors.sh                   |  6 ++++++
 t/t9137-git-svn-dcommit-clobber-series.sh |  4 ++--
 t/t9350-fast-export.sh                    |  2 +-
 t/t9850-shell.sh                          |  2 +-
 t/test-lib.sh                             |  1 +
 71 files changed, 281 insertions(+), 93 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index c9376dffb58..1aaa6bf5ae8 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,6 +5,12 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping ignores tests; Perl not available'
+	test_done
+fi
+
 init_vars () {
 	global_excludes="global-excludes"
 }
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 3f6433d3045..9c3738ebb3f 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -619,7 +619,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success 'required process filter should process multiple packets' '
+test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +684,7 @@ test_expect_success 'required process filter should process multiple packets' '
 	)
 '
 
-test_expect_success 'required process filter with clean error should fail' '
+test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index 4287ed3fbb3..ba4c0442b85 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index bac90465406..760cf69087f 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -4,6 +4,12 @@ test_description='test trace2 facility (perf target)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping trace2 tests; Perl not available'
+	test_done
+fi
+
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_PERF_BRIEF
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 4618ffc108e..5e0a1fa176d 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,7 +643,7 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success 'basic: can write large commit message' '
+test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	perl -e "
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index e2708e11d5b..fa1e2f9eef8 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,7 +139,7 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success 'small block size fails with large reflog message' '
+test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 398865d6ebe..a574da3df53 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1270,7 +1270,7 @@ extract_batch_output () {
     ' "$@"
 }
 
-test_expect_success 'cat-file --batch-all-objects --batch ignores replace' '
+test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '
 	git cat-file --batch-all-objects --batch >actual.raw &&
 	extract_batch_output $orig <actual.raw >actual &&
 	{
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index a0481139de5..b3cf53ff8c9 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -205,7 +205,7 @@ test_expect_success 'too-short tree' '
 	grep "too-short tree object" err
 '
 
-test_expect_success 'malformed mode in tree' '
+test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "9100644 \0$bin_oid" >tree-with-malformed-mode &&
@@ -213,7 +213,7 @@ test_expect_success 'malformed mode in tree' '
 	grep "malformed mode in tree entry" err
 '
 
-test_expect_success 'empty filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	printf "100644 \0$bin_oid" >tree-with-empty-filename &&
@@ -221,7 +221,7 @@ test_expect_success 'empty filename in tree' '
 	grep "empty filename in tree entry" err
 '
 
-test_expect_success 'duplicate filename in tree' '
+test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
 	hex_oid=$(echo foo | git hash-object --stdin -w) &&
 	bin_oid=$(echo $hex_oid | hex2oct) &&
 	{
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index c291a2b33d7..4977998e205 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,13 +41,13 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
 	perl -e "print reverse <>" <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
 	perl -e "print reverse <>" <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1142d..01050453762 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -346,7 +346,7 @@ test_expect_success 'unparseable tree object' '
 	test_grep ! "fatal: empty filename in tree entry" out
 '
 
-test_expect_success 'tree entry with type mismatch' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with type mismatch' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	test_when_finished "remove_object \$commit" &&
@@ -364,7 +364,7 @@ test_expect_success 'tree entry with type mismatch' '
 	test_grep ! "dangling blob" out
 '
 
-test_expect_success 'tree entry with bogus mode' '
+test_expect_success PERL_TEST_HELPERS 'tree entry with bogus mode' '
 	test_when_finished "remove_object \$blob" &&
 	test_when_finished "remove_object \$tree" &&
 	blob=$(echo blob | git hash-object -w --stdin) &&
@@ -984,7 +984,7 @@ corrupt_index_checksum () {
 
 # Corrupt the checksum on the index and then
 # verify that only fsck notices.
-test_expect_success 'detect corrupt index file in fsck' '
+test_expect_success PERL_TEST_HELPERS 'detect corrupt index file in fsck' '
 	cp .git/index .git/index.backup &&
 	test_when_finished "mv .git/index.backup .git/index" &&
 	corrupt_index_checksum &&
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index f5bf16abcd8..502b1572059 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,7 +63,7 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'ls-files -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
@@ -101,7 +101,7 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-index -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
@@ -111,7 +111,7 @@ test_expect_success 'diff-index -z does not quote funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success 'diff-tree -z does not quote funny filename' '
+test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68dbc0..782d97fb7df 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff various tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83fb8a4..2782b1fc183 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -448,7 +448,7 @@ cat >>expect.no-threading <<EOF
 ---
 EOF
 
-test_expect_success 'no threading' '
+test_expect_success PERL_TEST_HELPERS 'no threading' '
 	git checkout side &&
 	check_threading expect.no-threading main
 '
@@ -466,11 +466,11 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread' '
+test_expect_success PERL_TEST_HELPERS 'thread' '
 	check_threading expect.thread --thread main
 '
 
-test_expect_success '--thread overrides format.thread=deep' '
+test_expect_success PERL_TEST_HELPERS '--thread overrides format.thread=deep' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
@@ -490,7 +490,7 @@ In-Reply-To: <1>
 References: <1>
 EOF
 
-test_expect_success 'thread in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread in-reply-to' '
 	check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 		--thread main
 '
@@ -512,7 +512,7 @@ In-Reply-To: <0>
 References: <0>
 EOF
 
-test_expect_success 'thread cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter' '
 	check_threading expect.cover-letter --cover-letter --thread main
 '
 
@@ -538,12 +538,12 @@ References: <1>
 	<0>
 EOF
 
-test_expect_success 'thread cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread cover-letter in-reply-to' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread main
 '
 
-test_expect_success 'thread explicit shallow' '
+test_expect_success PERL_TEST_HELPERS 'thread explicit shallow' '
 	check_threading expect.cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=shallow main
 '
@@ -562,7 +562,7 @@ References: <0>
 	<1>
 EOF
 
-test_expect_success 'thread deep' '
+test_expect_success PERL_TEST_HELPERS 'thread deep' '
 	check_threading expect.deep --thread=deep main
 '
 
@@ -584,7 +584,7 @@ References: <1>
 	<2>
 EOF
 
-test_expect_success 'thread deep in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep in-reply-to' '
 	check_threading expect.deep-irt  --thread=deep \
 		--in-reply-to="<test.message>" main
 '
@@ -609,7 +609,7 @@ References: <0>
 	<2>
 EOF
 
-test_expect_success 'thread deep cover-letter' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter' '
 	check_threading expect.deep-cl --cover-letter --thread=deep main
 '
 
@@ -638,27 +638,27 @@ References: <1>
 	<3>
 EOF
 
-test_expect_success 'thread deep cover-letter in-reply-to' '
+test_expect_success PERL_TEST_HELPERS 'thread deep cover-letter in-reply-to' '
 	check_threading expect.deep-cl-irt --cover-letter \
 		--in-reply-to="<test.message>" --thread=deep main
 '
 
-test_expect_success 'thread via config' '
+test_expect_success PERL_TEST_HELPERS 'thread via config' '
 	test_config format.thread true &&
 	check_threading expect.thread main
 '
 
-test_expect_success 'thread deep via config' '
+test_expect_success PERL_TEST_HELPERS 'thread deep via config' '
 	test_config format.thread deep &&
 	check_threading expect.deep main
 '
 
-test_expect_success 'thread config + override' '
+test_expect_success PERL_TEST_HELPERS 'thread config + override' '
 	test_config format.thread deep &&
 	check_threading expect.thread --thread main
 '
 
-test_expect_success 'thread config + --no-thread' '
+test_expect_success PERL_TEST_HELPERS 'thread config + --no-thread' '
 	test_config format.thread deep &&
 	check_threading expect.no-threading --no-thread main
 '
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index f1efe482a59..189294de7ef 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -239,7 +239,7 @@ check_external_diff 128 empty  error 2 on  --quiet
 
 echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
 
-test_expect_success 'force diff with "diff"' '
+test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success 'diff --cached' '
+test_expect_success PERL_TEST_HELPERS 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index 32b6e9a4e76..a92a42990b1 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success "$test_description" '
+test_expect_success PERL_TEST_HELPERS "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index daebf9796f5..c7d8eb12453 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,6 +4,12 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff textconv tests; Perl not available'
+	test_done
+fi
+
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index c4394a27b56..cbe50b15772 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -70,7 +70,7 @@ test_expect_success 'setup textconv' '
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success 'rewrite diff respects textconv' '
+test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
 	git diff -B >diff &&
 	grep "dissimilarity index" diff &&
 	grep "^-61" diff &&
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2fce4a98977..16266dff2af 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -13,6 +13,12 @@ test_description='test tree diff when trees have duplicate entries'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping diff duplicates tests; Perl not available'
+	test_done
+fi
+
 # make_tree_entry <mode> <mode> <sha1>
 #
 # We have to rely on perl here because not all printfs understand
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index d370ecfe0d9..59d38793ae6 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,6 +11,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply-binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 0784ba033a4..6f414ad27f5 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,6 +10,12 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping apply reverse tests; Perl not available'
+	test_done
+fi
+
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c80eae..4794510d70d 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success 'am works with multi-line in-body headers' '
+test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b0a3e849841..50fe8b0fd05 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,6 +27,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rerere tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f81e42a84d5..8f2ba98963f 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -698,7 +698,7 @@ test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trail
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:unfold) unfolds trailers' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' '
 	git log --no-walk --pretty="%(trailers:unfold)" >actual &&
 	{
 		unfold <trailers &&
@@ -707,7 +707,7 @@ test_expect_success '%(trailers:unfold) unfolds trailers' '
 	test_cmp expect actual
 '
 
-test_expect_success ':only and :unfold work together' '
+test_expect_success PERL_TEST_HELPERS ':only and :unfold work together' '
 	git log --no-walk --pretty="%(trailers:only,unfold)" >actual &&
 	git log --no-walk --pretty="%(trailers:unfold,only)" >reverse &&
 	test_cmp actual reverse &&
@@ -754,7 +754,7 @@ test_expect_success '%(trailers:key=foo) handles multiple lines even if folded'
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '
+test_expect_success PERL_TEST_HELPERS '%(trailers:key=foo,unfold) properly unfolds' '
 	git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual &&
 	unfold <trailers | grep Signed-off-by >expect &&
 	test_cmp expect actual
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 3f163dc3969..8910d53cac1 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -738,20 +738,20 @@ check_corrupt_graph () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'Bloom reader notices too-small data chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
 	check_corrupt_graph BDAT clear 00000000 &&
 	echo "warning: ignoring too-small changed-path chunk" \
 		"(4 < 12) in commit-graph file" >expect.err &&
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
 	check_corrupt_graph BIDX 12 FFFFFFFF &&
 	# use grep to avoid depending on exact chunk size
 	grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
 '
 
-test_expect_success 'Bloom reader notices too-small index chunk' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
 	# replace the index with a single entry, making most
 	# lookups out-of-bounds
 	check_corrupt_graph BIDX clear 00000000 &&
@@ -760,7 +760,7 @@ test_expect_success 'Bloom reader notices too-small index chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'Bloom reader notices out-of-order index offsets' '
+test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
 	# we do not know any real offsets, but we can pick
 	# something plausible; we should not get to the point of
 	# actually reading from the bogus offsets anyway.
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 50344e17ca1..51749951916 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -4,6 +4,12 @@ test_description='test corner cases of git-archive'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping archive corner cases tests; Perl not available'
+	test_done
+fi
+
 # the 10knuls.tar file is used to test for an empty git generated tar
 # without having to invoke tar because an otherwise valid empty GNU tar
 # will be considered broken by {Open,Net}BSD tar
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 5ac8d39094b..143856c29f1 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,6 +7,12 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pack-object tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	rm -f .git/index* &&
 	perl -e "print \"a\" x 4096;" >a &&
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index de58ca654a1..ac5e370e1e4 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,7 +99,7 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first object' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
@@ -156,7 +156,7 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success 'create corruption in data of first delta' '
+test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 621bbbdd26e..81987296235 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 32cf4227451..cd947b5a5ef 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -87,7 +87,7 @@ max_chain() {
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success 'packing produces a long delta' '
+test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success '--depth limits depth' '
+test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success '--depth=0 disables deltas' '
+test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success 'negative depth disables deltas' '
+test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index f68f64cd85e..0b3404f58fe 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -837,7 +837,7 @@ check_corrupt_chunk () {
 	test_cmp expect.out out
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	# make it big enough that the graph file is plausible,
 	# otherwise we hit an earlier check
 	check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
@@ -848,7 +848,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices fanout/lookup table mismatch' '
+test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' '
 	check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph OID lookup chunk is the wrong size
@@ -857,7 +857,7 @@ test_expect_success 'reader notices fanout/lookup table mismatch' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# Rather than try to corrupt a specific hash, we will just
 	# wreck them all. But we cannot just set them all to 0xFFFFFFFF or
 	# similar, as they are used for hi/lo starts in a binary search (so if
@@ -873,7 +873,7 @@ test_expect_success 'reader notices out-of-bounds fanout' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small commit data chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' '
 	check_corrupt_chunk CDAT clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph commit data chunk is wrong size
@@ -882,7 +882,7 @@ test_expect_success 'reader notices too-small commit data chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds extra edge' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' '
 	check_corrupt_chunk EDGE clear &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph extra-edges pointer out of bounds
@@ -890,7 +890,7 @@ test_expect_success 'reader notices out-of-bounds extra edge' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small generations chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' '
 	check_corrupt_chunk GDA2 clear 00000000 &&
 	cat >expect.err <<-\EOF &&
 	error: commit-graph generations chunk is wrong size
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 0f215ad2e88..bd75dea9501 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1120,7 +1120,7 @@ corrupt_chunk () {
 	corrupt_chunk_file $midx "$@"
 }
 
-test_expect_success 'reader notices too-small oid fanout chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
 	corrupt_chunk OIDF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1130,7 +1130,7 @@ test_expect_success 'reader notices too-small oid fanout chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small oid lookup chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '
 	corrupt_chunk OIDL clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1140,7 +1140,7 @@ test_expect_success 'reader notices too-small oid lookup chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader notices too-small pack names chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '
 	# There is no NUL to terminate the name here, so the
 	# chunk is too short.
 	corrupt_chunk PNAM clear 70656666 &&
@@ -1151,7 +1151,7 @@ test_expect_success 'reader notices too-small pack names chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader handles unaligned chunks' '
+test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '
 	# A 9-byte PNAM means all of the subsequent chunks
 	# will no longer be 4-byte aligned, but it is still
 	# a valid one-pack chunk on its own (it is "foo.pack\0").
@@ -1165,7 +1165,7 @@ test_expect_success 'reader handles unaligned chunks' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices too-small object offset chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '
 	corrupt_chunk OOFF clear 00000000 &&
 	test_must_fail git log 2>err &&
 	cat >expect <<-\EOF &&
@@ -1175,7 +1175,7 @@ test_expect_success 'reader notices too-small object offset chunk' '
 	test_cmp expect err
 '
 
-test_expect_success 'reader bounds-checks large offset table' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '
 	# re-use the objects64 dir here to cheaply get access to a midx
 	# with large offsets.
 	git init repo &&
@@ -1197,7 +1197,7 @@ test_expect_success 'reader bounds-checks large offset table' '
 	)
 '
 
-test_expect_success 'reader notices too-small revindex chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '
 	# We only get a revindex with bitmaps (and likewise only
 	# load it when they are asked for).
 	test_config repack.writeBitmaps true &&
@@ -1214,7 +1214,7 @@ test_expect_success 'reader notices too-small revindex chunk' '
 	test_cmp expect.err err
 '
 
-test_expect_success 'reader notices out-of-bounds fanout' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
 	# This is similar to the out-of-bounds fanout test in t5318. The values
 	# in adjacent entries should be large but not identical (they
 	# are used as hi/lo starts for a binary search, which would then abort
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index a32be3867df..49a057cc2eb 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -401,7 +401,7 @@ test_expect_success 'verify across alternates' '
 	)
 '
 
-test_expect_success 'reader bounds-checks base-graph chunk' '
+test_expect_success PERL_TEST_HELPERS 'reader bounds-checks base-graph chunk' '
 	git clone --no-hardlinks . corrupt-base-chunk &&
 	(
 		cd corrupt-base-chunk &&
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index d27557b9b04..627f8b4efdc 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success 'pack.preferBitmapTips' '
+	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh
index a766a3e3f84..d8891e6a922 100755
--- a/t/t5328-commit-graph-64bit-time.sh
+++ b/t/t5328-commit-graph-64bit-time.sh
@@ -74,7 +74,7 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
 	git -C repo-uint32-max commit-graph verify
 '
 
-test_expect_success 'reader notices out-of-bounds generation overflow' '
+test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds generation overflow' '
 	graph=.git/objects/info/commit-graph &&
 	test_when_finished "rm -rf $graph" &&
 	git commit-graph write --reachable &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 3905cb6e4f1..1059ff45fe4 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,6 +6,12 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
+	test_done
+fi
+
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16e133..571e8f1bc59 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -268,7 +268,7 @@ extract_ref_advertisement () {
 	'
 }
 
-test_expect_success 'receive-pack de-dupes .have lines' '
+test_expect_success PERL_TEST_HELPERS 'receive-pack de-dupes .have lines' '
 	git init shared &&
 	git -C shared commit --allow-empty -m both &&
 	git clone -s shared fork &&
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 0b28e4e452f..6a009fdcd71 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -20,7 +20,7 @@ extract_haves () {
 	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
 }
 
-test_expect_success 'with core.alternateRefsCommand' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success 'with core.alternateRefsPrefixes' '
+test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 845ca43ea0a..febe4410417 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping tagfollow tests; Perl not available'
+	test_done
+fi
+
 # End state of the repository:
 #
 #         T - tag1          S - tag2
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 58074506c59..438250c75ed 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -359,7 +359,7 @@ test_expect_success \
 	grep "Cannot demote unterminatedheader" act
 '
 
-test_expect_success 'badFilemode is not a strict error' '
+test_expect_success PERL_TEST_HELPERS 'badFilemode is not a strict error' '
 	git init --bare badmode.git &&
 	tree=$(
 		cd badmode.git &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 5f350facf5e..432a2264e6f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -8,6 +8,12 @@ test_description='Per branch config variables affects "git fetch".
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch tests; Perl not available'
+	test_done
+fi
+
 D=$(pwd)
 
 test_expect_success setup '
diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh
index 37558226290..95d0f33b295 100755
--- a/t/t5532-fetch-proxy.sh
+++ b/t/t5532-fetch-proxy.sh
@@ -4,6 +4,12 @@ test_description='fetching via git:// using core.gitproxy'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping fetch proxy tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup remote repo' '
 	git init remote &&
 	(cd remote &&
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index c91a62b77af..342d0423c92 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 37f7547a4ca..77d20d19110 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 761fdfcfe6c..b0d4ea78015 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -7,6 +7,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
+
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http fetch smart tests; Perl not available'
+	test_done
+fi
+
 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
 start_httpd
 
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index f3b158274c4..b6ee06f5c8f 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -4,6 +4,12 @@ test_description='test git-http-backend respects CONTENT_LENGTH'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping http backend content tests; Perl not available'
+	test_done
+fi
+
 test_lazy_prereq GZIP 'gzip --version'
 
 verify_http_result() {
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d0c18660e33..d743d986c40 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -649,7 +649,7 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
 	git -C replay.git index-pack -v --stdin <tmp.pack
 '
 
-test_expect_success 'clone on case-insensitive fs' '
+test_expect_success PERL_TEST_HELPERS 'clone on case-insensitive fs' '
 	git init icasefs &&
 	(
 		cd icasefs &&
@@ -662,7 +662,7 @@ test_expect_success 'clone on case-insensitive fs' '
 	)
 '
 
-test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
+test_expect_success PERL_TEST_HELPERS,CASE_INSENSITIVE_FS 'colliding file detection' '
 	grep X icasefs/warning &&
 	grep x icasefs/warning &&
 	test_grep "the following paths have collided" icasefs/warning
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 46504519643..bc7e0fec8dc 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -751,7 +751,7 @@ replace_packfile () {
 	}' >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
-test_expect_success 'upon cloning, check that all refs point to objects' '
+test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -784,7 +784,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -825,7 +825,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
 	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
-test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
+test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 678a346ed06..200bf06ecb3 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success 'ignore very large set of prefixes' '
+test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index d3df81e7852..ad5e772cd72 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success 'when server sends "ready", expect DELIM' '
+test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1140,7 +1140,7 @@ test_expect_success 'when server sends "ready", expect DELIM' '
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success 'when server does not send "ready", expect FLUSH' '
+test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1446,7 +1446,7 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
 	URI="$HTTPD_URL/one_time_perl/server" &&
 
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 191097171bc..f59d47aa6c6 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,6 +4,12 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
+	test_done
+fi
+
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index d2cc69a17e4..9a420cf5605 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -4,6 +4,12 @@ test_description='handling of promisor remote advertisement'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping promisor remote capabilities tests; Perl not available'
+	test_done
+fi
+
 GIT_TEST_MULTI_PACK_INDEX=0
 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index daa009c9a1b..5e1482aff78 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,6 +7,12 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list bisect tests; Perl not available'
+	test_done
+fi
+
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 0d7055d46d4..02dd4127aff 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,6 +8,12 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list topo-order tests; Perl not available'
+	test_done
+fi
+
 list_duplicates()
 {
     "$@" | sort | uniq -d
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index bad02cf5b83..6131c361094 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list with bad commit tests; Perl not available'
+	test_done
+fi
+
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 39793cbbd66..8074185742c 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,7 +26,7 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success '--reverse --parents --full-history combines correctly' '
+test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
 	git rev-list --parents --full-history main -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
@@ -34,7 +34,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' '
 	test_cmp expected actual
 	'
 
-test_expect_success '--boundary does too' '
+test_expect_success PERL_TEST_HELPERS '--boundary does too' '
 	git rev-list --boundary --parents --full-history main ^root -- foo |
 		perl -e "print reverse <>" > expected &&
 	git rev-list --boundary --reverse --parents --full-history \
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 22dfd6d978e..eb98b3919c8 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -4,6 +4,12 @@ test_description='git rev-list should handle unexpected object types'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list unexpected objects tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup well-formed objects' '
 	blob="$(printf "foo" | git hash-object -w --stdin)" &&
 	tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 3385fe9f130..6a74be576a2 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,6 +4,12 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping rev-list disk usage tests; Perl not available'
+	test_done
+fi
+
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a5c77943854..732a4d3171e 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,6 +10,12 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping for-each-ref tests; Perl not available'
+	test_done
+fi
+
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 932c26cb45b..49aae183829 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,7 +661,7 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success 'setup large log output' '
+test_expect_success PERL_TEST_HELPERS 'setup large log output' '
 	perl -e "
 		print \"this is a long commit message\" x 50000
 	" >commit-msg &&
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 0c605fd271a..14069600a2f 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,6 +4,12 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping submodule dash URL tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index b2070d4e39f..14c41b2cb7c 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,7 +1064,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success 'status -z implies porcelain' '
+test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
 	git status --porcelain |
 	perl -pe "s/\012/\000/g" >expect &&
 	git status -z >output &&
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index 90ebb64f46e..b2730d200c8 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,6 +4,12 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping grep binary tests; Perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index d7167f55397..609845aeb1e 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping annotate tests; Perl not available'
+	test_done
+fi
+
 PROG='git annotate'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index e98993276a6..b40199df231 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 07a287ffd3e..5cb16872081 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,6 +4,12 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame textconv tests; Perl not available'
+	test_done
+fi
+
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh
index c66494f5ba7..388057245c8 100755
--- a/t/t8011-blame-split-file.sh
+++ b/t/t8011-blame-split-file.sh
@@ -81,7 +81,7 @@ do
 		git blame --root -C --$output combined >output
 	'
 
-	test_expect_success "$output output finds correct commits" '
+	test_expect_success PERL_TEST_HELPERS "$output output finds correct commits" '
 		generate_expect >expect <<-\EOF &&
 		5 base
 		1 modified
@@ -93,7 +93,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct filenames" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct filenames" '
 		generate_expect >expect <<-\EOF &&
 		11 one
 		11 two
@@ -102,7 +102,7 @@ do
 		test_cmp expect actual
 	'
 
-	test_expect_success "$output output shows correct previous pointer" '
+	test_expect_success PERL_TEST_HELPERS "$output output shows correct previous pointer" '
 		generate_expect >expect <<-EOF &&
 		5 NONE
 		1 $(git rev-parse modified^) one
diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh
index c3a5f6d01ff..3d77352650f 100755
--- a/t/t8012-blame-colors.sh
+++ b/t/t8012-blame-colors.sh
@@ -7,6 +7,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
+if ! test_have_prereq PERL_TEST_HELPERS
+then
+	skip_all='skipping blame colors tests; Perl not available'
+	test_done
+fi
+
 PROG='git blame -c'
 . "$TEST_DIRECTORY"/annotate-tests.sh
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index 067b15bad25..a9d38be997c 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,7 +15,7 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' '
+test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
@@ -37,7 +37,7 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success 'change file but in unrelated area' "
+test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
 	perl -i.bak -p -e 's/^4\$/4444/' file &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 40427883ec6..0781a8d6ace 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -610,7 +610,7 @@ test_expect_success 'directory becomes symlink'        '
 	(cd result && git show main:foo)
 '
 
-test_expect_success 'fast-export quotes pathnames' '
+test_expect_success PERL_TEST_HELPERS 'fast-export quotes pathnames' '
 	git init crazy-paths &&
 	test_config -C crazy-paths core.protectNTFS false &&
 	(cd crazy-paths &&
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index 36566ace21b..f619b60f226 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,7 +29,7 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success 'shell complains of overlong commands' '
+test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
 	perl -e "print \"a\" x 2**12 for (0..2**19)" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a62699d6c79..59162a3c834 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1706,6 +1706,7 @@ test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2
 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
 test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK
 test -n "$GIT_VALGRIND_ENABLED" && test_set_prereq VALGRIND
+test -n "$PERL_PATH" && test_set_prereq PERL_TEST_HELPERS
 
 if test -z "$GIT_TEST_CHECK_CACHE_TREE"
 then

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 07/20] t: adapt existing PERL prerequisites
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (5 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:05   ` [PATCH v4 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
                     ` (13 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A couple of our tests depend on the PERL prerequisite even though it
isn't needed. These tests fall into one of the following classes:

  - The underlying logic used to be implemented in Perl but isn't
    anymore. Here we can simply drop the dependency altogether.

  - The test logic used to depend on Perl but doesn't anymore. Again, we
    can simply drop the dependency.

  - The test logic still relies on a Perl interpreter. These tests
    should use the newly introduced PERL_TEST_HELPERS prerequisite.

Adapt test cases accordingly.

Note that in t1006 we have to introduce another new prerequisite
depending on whether or not the IPC::Open2 module is available. Funny
enough, when starting to use `test_lazy_prereq` to do so we also get a
conflict of variables with the "script" variable that contains the Perl
logic because `test_run_lazy_prereq_` also sets that variable. We thus
rename the variable in t1006 to "perl_script".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh                 | 10 +++++-----
 t/t0090-cache-tree.sh                 |  4 ++--
 t/t1006-cat-file.sh                   | 14 +++++++++-----
 t/t7501-commit-basic-functionality.sh |  6 +++---
 4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 9c3738ebb3f..4a892a91780 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -841,7 +841,7 @@ test_expect_success 'process filter abort stops processing of all further files'
 	)
 '
 
-test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
+test_expect_success 'invalid process filter must fail (and not hang!)' '
 	test_config_global filter.protocol.process cat &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&
@@ -1111,19 +1111,19 @@ do
 	branch) opt='-f HEAD' ;;
 	esac
 
-	test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
+	test_expect_success TTY "delayed checkout shows progress by default on tty ($mode checkout)" '
 		test_delayed_checkout_progress test_terminal git checkout $opt
 	'
 
-	test_expect_success PERL "delayed checkout omits progress on non-tty ($mode checkout)" '
+	test_expect_success "delayed checkout omits progress on non-tty ($mode checkout)" '
 		test_delayed_checkout_progress ! git checkout $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
+	test_expect_success TTY "delayed checkout omits progress with --quiet ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt
 	'
 
-	test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
+	test_expect_success TTY "delayed checkout honors --[no]-progress ($mode checkout)" '
 		test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt &&
 		test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt
 	'
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index ab80c9ef135..d9015882946 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -128,7 +128,7 @@ test_expect_success 'second commit has cache-tree' '
 	test_cache_tree
 '
 
-test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' '
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
 	test_when_finished "git reset --hard" &&
 	cat <<-\EOT >foo.c &&
 	int foo()
@@ -162,7 +162,7 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
 	test_cache_tree expected.status
 '
 
-test_expect_success PERL 'commit -p with shrinking cache-tree' '
+test_expect_success 'commit -p with shrinking cache-tree' '
 	mkdir -p deep/very-long-subdir &&
 	echo content >deep/very-long-subdir/file &&
 	git add deep &&
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index a574da3df53..0a22b0a7b8e 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -1323,7 +1323,7 @@ test_expect_success 'batch-command flush without --buffer' '
 	grep "^fatal:.*flush is only for --buffer mode.*" err
 '
 
-script='
+perl_script='
 use warnings;
 use strict;
 use IPC::Open2;
@@ -1345,12 +1345,16 @@ $? == 0 or die "\$?=$?";
 
 expect="$hello_oid blob $hello_size"
 
-test_expect_success PERL '--batch-check is unbuffered by default' '
-	perl -e "$script" -- --batch-check $hello_oid "$expect"
+test_lazy_prereq PERL_IPC_OPEN2 '
+	perl -MIPC::Open2 -e "exit 0"
 '
 
-test_expect_success PERL '--batch-command info is unbuffered by default' '
-	perl -e "$script" -- --batch-command $hello_oid "$expect" "info "
+test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-check $hello_oid "$expect"
+'
+
+test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '
+	perl -e "$perl_script" -- --batch-command $hello_oid "$expect" "info "
 '
 
 test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index cc12f99f115..a37509f0043 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -46,7 +46,7 @@ test_expect_success 'paths and -a do not mix' '
 	test_must_fail git commit -m foo -a file
 '
 
-test_expect_success PERL 'can use paths with --interactive' '
+test_expect_success 'can use paths with --interactive' '
 	echo bong-o-bong >file &&
 	# 2: update, 1:st path, that is all, 7: quit
 	test_write_lines 2 1 "" 7 |
@@ -345,12 +345,12 @@ test_expect_success 'overriding author from command line' '
 	grep Rubber.Duck output
 '
 
-test_expect_success PERL 'interactive add' '
+test_expect_success 'interactive add' '
 	echo 7 | test_must_fail git commit --interactive >out &&
 	grep "What now" out
 '
 
-test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
+test_expect_success "commit --interactive doesn't change index if editor aborts" '
 	echo zoo >file &&
 	test_must_fail git diff --exit-code >diff1 &&
 	test_write_lines u "*" q |

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 08/20] meson: stop requiring Perl when tests are enabled
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (6 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
@ 2025-04-03  5:05   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
                     ` (12 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:05 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Perl interpreter used to be a strict dependency for running our test
suite. This requirement is explicit in the Meson build system, where we
require Perl to be present unless tests have been disabled.

With the preceding commits we have loosened this restriction so that it
is now possible to run tests when Perl is unavailable. Loosen the above
requirement accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index efe2871c9db..d6e27b236fa 100644
--- a/meson.build
+++ b/meson.build
@@ -772,7 +772,7 @@ endif
 # features. It is optional if you want to neither execute tests nor use any of
 # these optional features.
 perl_required = get_option('perl')
-if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
+if get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
   perl_required = true
 endif
 

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 09/20] Makefile: stop requiring Perl when running tests
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (7 preceding siblings ...)
  2025-04-03  5:05   ` [PATCH v4 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
                     ` (11 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The Makefile for our tests has a couple of targets that depend on Perl.
Adapt those targets to only run conditionally in case Perl is available
on the system so that it becomes possible to run the test suite without
Perl.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/Makefile | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/t/Makefile b/t/Makefile
index 2994eb5fa9a..791e0a09789 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -59,16 +59,21 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT
 
 all:: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean check-chainlint check-meson $(TEST_LINT)
+test: pre-clean check-meson $(TEST_LINT)
 	$(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
 
+ifneq ($(PERL_PATH),)
+test: check-chainlint
+prove: check-chainlint
+endif
+
 failed:
 	@failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \
 		grep -l '^failed [1-9]' *.counts | \
 		sed -n 's/\.counts$$/.sh/p') && \
 	test -z "$$failed" || $(MAKE) $$failed
 
-prove: pre-clean check-chainlint $(TEST_LINT)
+prove: pre-clean $(TEST_LINT)
 	@echo "*** prove (shell & unit tests) ***"
 	@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
 	$(MAKE) clean-except-prove-cache
@@ -132,8 +137,13 @@ check-meson:
 		fi; \
 	done
 
-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
+test-lint: test-lint-duplicates test-lint-executable \
 	test-lint-filenames
+ifneq ($(PERL_PATH),)
+test-lint: test-lint-shell-syntax
+else
+GIT_TEST_CHAIN_LINT = 0
+endif
 ifneq ($(GIT_TEST_CHAIN_LINT),0)
 test-lint: test-chainlint
 endif

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 10/20] t: refactor tests depending on Perl transliteration operator
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (8 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
                     ` (10 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform character
transliteration via the "y/" or "tr/" operator. These usecases can be
trivially replaced with tr(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-sha1.sh    |  4 ++--
 t/lib-diff.sh            |  4 ++--
 t/t3300-funny-names.sh   | 12 ++++++------
 t/t4020-diff-external.sh |  6 +++---
 t/t4103-apply-binary.sh  | 12 +++---------
 t/t4116-apply-reverse.sh | 10 ++--------
 t/t4200-rerere.sh        |  2 +-
 7 files changed, 19 insertions(+), 31 deletions(-)

diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index bf387d3db14..f03b784ddc2 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -15,7 +15,7 @@ do
 			{
 				test -z "$pfx" || echo "$pfx"
 				dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-				perl -pe 'y/\000/g/'
+				tr "\000" "g"
 			} | ./t/helper/test-tool $sha1 $cnt
 		)
 		if test "$expect" = "$actual"
@@ -61,7 +61,7 @@ do
 		{
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-			perl -pe 'y/\000/g/'
+			tr "\000" "g"
 		} | sha1sum |
 		sed -e 's/ .*//'
 	)
diff --git a/t/lib-diff.sh b/t/lib-diff.sh
index c4606bd4b7f..12b3c8fcc6a 100644
--- a/t/lib-diff.sh
+++ b/t/lib-diff.sh
@@ -21,8 +21,8 @@ compare_diff_raw_z () {
     # Also we do not check SHA1 hash generation in this test, which
     # is a job for t0000-basic.sh
 
-    perl -pe 'y/\000/\012/' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
-    perl -pe 'y/\000/\012/' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
+    tr "\000" "\012" <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
+    tr "\000" "\012" <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
     test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 502b1572059..dd0586b0073 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -63,14 +63,14 @@ test_expect_success 'ls-files quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-files -z does not quote funny filename' '
+test_expect_success 'ls-files -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	just space
 	no-funny
 	tabs	," (dq) and spaces
 	EOF
 	git ls-files -z >ls-files.z &&
-	perl -pe "y/\000/\012/" <ls-files.z >current &&
+	tr "\000" "\012" <ls-files.z >current &&
 	test_cmp expected current
 '
 
@@ -101,23 +101,23 @@ test_expect_success 'diff-tree --name-status quotes funny filename' '
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-index -z does not quote funny filename' '
+test_expect_success 'diff-index -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-index -z --name-status $t0 >diff-index.z &&
-	perl -pe "y/\000/\012/" <diff-index.z >current &&
+	tr "\000" "\012" <diff-index.z >current &&
 	test_cmp expected current
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff-tree -z does not quote funny filename' '
+test_expect_success 'diff-tree -z does not quote funny filename' '
 	cat >expected <<-\EOF &&
 	A
 	tabs	," (dq) and spaces
 	EOF
 	git diff-tree -z --name-status $t0 $t1 >diff-tree.z &&
-	perl -pe y/\\000/\\012/ <diff-tree.z >current &&
+	tr "\000" "\012" <diff-tree.z >current &&
 	test_cmp expected current
 '
 
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 189294de7ef..c8a23d51483 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -237,9 +237,9 @@ check_external_diff   0 empty  empty 0 on  --quiet
 check_external_diff   1 empty  empty 1 on  --quiet
 check_external_diff 128 empty  error 2 on  --quiet
 
-echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file
+echo NULZbetweenZwords | tr "Z" "\000" > file
 
-test_expect_success PERL_TEST_HELPERS 'force diff with "diff"' '
+test_expect_success 'force diff with "diff"' '
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	echo >.gitattributes "file diff" &&
@@ -300,7 +300,7 @@ test_expect_success 'external diff with autocrlf = true' '
 	test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c)
 '
 
-test_expect_success PERL_TEST_HELPERS 'diff --cached' '
+test_expect_success 'diff --cached' '
 	test_config core.autocrlf true &&
 	git add file &&
 	git update-index --assume-unchanged file &&
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index 59d38793ae6..8e302a5a57e 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -11,12 +11,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply-binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >file1 <<-\EOF &&
 	A quick brown fox jumps over the lazy dog.
@@ -32,10 +26,10 @@ test_expect_success 'setup' '
 	git commit -m "Initial Version" 2>/dev/null &&
 
 	git checkout -b binary &&
-	perl -pe "y/x/\000/" <file1 >file3 &&
+	tr "x" "\000" <file1 >file3 &&
 	cat file3 >file4 &&
 	git add file2 &&
-	perl -pe "y/\000/v/" <file3 >file1 &&
+	tr "y" "\000" <file3 >file1 &&
 	rm -f file2 &&
 	git update-index --add --remove file1 file2 file3 file4 &&
 	git commit -m "Second Version" &&
@@ -164,7 +158,7 @@ test_expect_success 'apply binary -p0 diff' '
 	test -z "$(git diff --name-status binary -- file3)"
 '
 
-test_expect_success 'reject truncated binary diff' '
+test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' '
 	do_reset &&
 
 	# this length is calculated to get us very close to
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index 6f414ad27f5..1e7beab0016 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -10,23 +10,17 @@ test_description='git apply in reverse
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping apply reverse tests; Perl not available'
-	test_done
-fi
-
 test_expect_success setup '
 
 	test_write_lines a b c d e f g h i j k l m n >file1 &&
-	perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 &&
+	tr "ijk" "\000\001\002" <file1 >file2 &&
 
 	git add file1 file2 &&
 	git commit -m initial &&
 	git tag initial &&
 
 	test_write_lines a b c g h i J K L m o n p q >file1 &&
-	perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 &&
+	tr "mon" "\000\001\002" <file1 >file2 &&
 
 	git commit -a -m second &&
 	git tag second &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 50fe8b0fd05..7fcca9ddad5 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -194,7 +194,7 @@ test_expect_success 'rerere updates postimage timestamp' '
 
 test_expect_success 'rerere clear' '
 	mv $rr/postimage .git/post-saved &&
-	echo "$sha1	a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
+	echo "$sha1	a1" | tr "\012" "\000" >.git/MERGE_RR &&
 	git rerere clear &&
 	! test -d $rr
 '

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 11/20] t: refactor tests depending on Perl substitution operator
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (9 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
                     ` (9 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a bunch of tests that use Perl to perform substitution via the
"s/" operator. These usecases can be trivially replaced with sed(1) and
tr(1).

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0008-ignores.sh                        | 10 ++--------
 t/t4029-diff-trailing-space.sh            |  5 +++--
 t/t4200-rerere.sh                         | 12 +++---------
 t/t5303-pack-corruption-resilience.sh     | 10 ++++++----
 t/t5310-pack-bitmaps.sh                   |  4 ++--
 t/t5534-push-signed.sh                    |  4 ++--
 t/t6011-rev-list-with-bad-commit.sh       | 20 +++++++++-----------
 t/t7416-submodule-dash-url.sh             |  9 ++-------
 t/t7508-status.sh                         |  4 ++--
 t/t8006-blame-textconv.sh                 |  8 +-------
 t/t9137-git-svn-dcommit-clobber-series.sh | 14 ++++++++------
 11 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 1aaa6bf5ae8..273d71411fe 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -5,12 +5,6 @@ test_description=check-ignore
 TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping ignores tests; Perl not available'
-	test_done
-fi
-
 init_vars () {
 	global_excludes="global-excludes"
 }
@@ -45,11 +39,11 @@ test_stderr () {
 }
 
 broken_c_unquote () {
-	"$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
+	sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0'
 }
 
 broken_c_unquote_verbose () {
-	"$PERL_PATH" -pe 's/	"/	/; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
+	sed -e 's/	"/	/' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000'
 }
 
 stderr_contains () {
diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh
index a92a42990b1..90cdde88d8b 100755
--- a/t/t4029-diff-trailing-space.sh
+++ b/t/t4029-diff-trailing-space.sh
@@ -18,7 +18,7 @@ index 5f6a263..8cb8bae 100644
 EOF
 exit 1
 
-test_expect_success PERL_TEST_HELPERS "$test_description" '
+test_expect_success "$test_description" '
 	printf "\nx\n" > f &&
 	before=$(git hash-object f) &&
 	before=$(git rev-parse --short $before) &&
@@ -31,7 +31,8 @@ test_expect_success PERL_TEST_HELPERS "$test_description" '
 	git config --bool diff.suppressBlankEmpty true &&
 	git diff f > actual &&
 	test_cmp exp actual &&
-	perl -i.bak -p -e "s/^\$/ /" exp &&
+	sed "s/^\$/ /" exp >exp.munged &&
+	mv exp.munged exp &&
 	git config --bool diff.suppressBlankEmpty false &&
 	git diff f > actual &&
 	test_cmp exp actual &&
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 7fcca9ddad5..204325f4d53 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -27,12 +27,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rerere tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	cat >a1 <<-\EOF &&
 	Some title
@@ -87,7 +81,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' '
 	test_might_fail git config --unset rerere.enabled &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep "^=======\$" $rr/preimage &&
 	! test -f $rr/postimage &&
@@ -100,7 +94,7 @@ test_expect_success 'rerere.enabled works, too' '
 	git reset --hard &&
 	test_must_fail git merge first &&
 
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	grep ^=======$ $rr/preimage
 '
@@ -110,7 +104,7 @@ test_expect_success 'set up rr-cache' '
 	git config rerere.enabled true &&
 	git reset --hard &&
 	test_must_fail git merge first &&
-	sha1=$(perl -pe "s/	.*//" .git/MERGE_RR) &&
+	sha1=$(sed "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1
 '
 
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index ac5e370e1e4..ab99c8b6850 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -99,11 +99,12 @@ test_expect_success '... and loose copy of first delta allows for partial recove
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first object' '
+test_expect_success 'create corruption in data of first object' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
+	sed "s/ base /abcdef/" ${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	test_must_fail git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
@@ -156,11 +157,12 @@ test_expect_success '... and then a repack "clears" the corruption' '
 	git cat-file blob $blob_3 > /dev/null
 '
 
-test_expect_success PERL_TEST_HELPERS 'create corruption in data of first delta' '
+test_expect_success 'create corruption in data of first delta' '
 	create_new_pack &&
 	git prune-packed &&
 	chmod +w ${pack}.pack &&
-	perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
+	sed "s/ delta1 /abcdefgh/" ${pack}.pack >${pack}.pack.munged &&
+	mv ${pack}.pack.munged ${pack}.pack &&
 	git cat-file blob $blob_1 > /dev/null &&
 	test_must_fail git cat-file blob $blob_2 > /dev/null &&
 	test_must_fail git cat-file blob $blob_3 > /dev/null
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 81987296235..a62b463eaf0 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -395,7 +395,7 @@ test_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -421,7 +421,7 @@ test_bitmap_cases () {
 
 			# mark the commits which did not receive bitmaps as preferred,
 			# and generate the bitmap again
-			perl -pe "s{^}{create refs/tags/include/$. }" <before |
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
 				git update-ref --stdin &&
 			git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
 
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 342d0423c92..2a782214ee1 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -177,7 +177,7 @@ test_expect_success GPGSSH 'ssh signed push sends push certificate' '
 	test_cmp expect dst/push-cert-status
 '
 
-test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed push not allowed' '
+test_expect_success GPG 'inconsistent push options in signed push not allowed' '
 	# First, invoke receive-pack with dummy input to obtain its preamble.
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
@@ -205,7 +205,7 @@ test_expect_success GPG,PERL_TEST_HELPERS 'inconsistent push options in signed p
 	# Tweak the push output to make the push option outside the cert
 	# different, then replay it on a fresh dst, checking that ff is not
 	# deleted.
-	perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
+	sed "s/\([^ ]\)bar/\1baz/" push >push.tweak &&
 	prepare_dst &&
 	git -C dst config receive.certnonceseed sekrit &&
 	git -C dst config receive.advertisepushoptions 1 &&
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index 6131c361094..b6f3344dbfb 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -4,12 +4,6 @@ test_description='git rev-list should notice bad commits'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list with bad commit tests; Perl not available'
-	test_done
-fi
-
 # Note:
 # - compression level is set to zero to make "corruptions" easier to perform
 # - reflog is disabled to avoid extra references which would twart the test
@@ -41,11 +35,15 @@ test_expect_success 'verify number of revisions' \
    first_commit=$(git rev-parse HEAD~3)
    '
 
-test_expect_success 'corrupt second commit object' \
-   '
-   perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
-   test_must_fail git fsck --full
-   '
+test_expect_success 'corrupt second commit object' '
+	for p in .git/objects/pack/*.pack
+	do
+		sed "s/second commit/socond commit/" "$p" >"$p.munged" &&
+		mv "$p.munged" "$p" ||
+		return 1
+	done &&
+	test_must_fail git fsck --full
+'
 
 test_expect_success 'rev-list should fail' '
 	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 14069600a2f..3d944a00e0d 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -4,12 +4,6 @@ test_description='check handling of disallowed .gitmodule urls'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping submodule dash URL tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	git config --global protocol.file.allow always
 '
@@ -39,7 +33,8 @@ test_expect_success 'fsck accepts protected dash' '
 '
 
 test_expect_success 'remove ./ protection from .gitmodules url' '
-	perl -i -pe "s{\./}{}" .gitmodules &&
+	sed "s|\./||" .gitmodules >.gitmodules.munged &&
+	mv .gitmodules.munged .gitmodules &&
 	git commit -am "drop protection"
 '
 
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 14c41b2cb7c..cdc1d6fcc78 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1064,9 +1064,9 @@ test_expect_success 'status -s submodule summary (clean submodule)' '
 	test_cmp expect output
 '
 
-test_expect_success PERL_TEST_HELPERS 'status -z implies porcelain' '
+test_expect_success 'status -z implies porcelain' '
 	git status --porcelain |
-	perl -pe "s/\012/\000/g" >expect &&
+	tr "\012" "\000" >expect &&
 	git status -z >output &&
 	test_cmp expect output
 '
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 5cb16872081..db1e2afb2ca 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -4,12 +4,6 @@ test_description='git blame textconv support'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping blame textconv tests; Perl not available'
-	test_done
-fi
-
 find_blame() {
 	sed -e 's/^[^(]*//'
 }
@@ -17,7 +11,7 @@ find_blame() {
 cat >helper <<'EOF'
 #!/bin/sh
 grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
-"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1"
+sed 's/^bin: /converted: /' "$1"
 EOF
 chmod +x helper
 
diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh
index a9d38be997c..b57a362bb98 100755
--- a/t/t9137-git-svn-dcommit-clobber-series.sh
+++ b/t/t9137-git-svn-dcommit-clobber-series.sh
@@ -15,13 +15,13 @@ test_expect_success 'initialize repo' '
 	test -e file
 	'
 
-test_expect_success PERL_TEST_HELPERS '(supposedly) non-conflicting change from SVN' '
+test_expect_success '(supposedly) non-conflicting change from SVN' '
 	test x"$(sed -n -e 58p < file)" = x58 &&
 	test x"$(sed -n -e 61p < file)" = x61 &&
 	svn_cmd co "$svnrepo" tmp &&
 	(cd tmp &&
-		perl -i.bak -p -e "s/^58$/5588/" file &&
-		perl -i.bak -p -e "s/^61$/6611/" file &&
+		sed -e "s/^58$/5588/" -e "s/^61$/6611/" file >file.munged &&
+		mv file.munged file &&
 		poke file &&
 		test x"$(sed -n -e 58p < file)" = x5588 &&
 		test x"$(sed -n -e 61p < file)" = x6611 &&
@@ -37,11 +37,13 @@ test_expect_success 'some unrelated changes to git' "
 	git commit -m bye-life life
 	"
 
-test_expect_success PERL_TEST_HELPERS 'change file but in unrelated area' "
+test_expect_success 'change file but in unrelated area' "
 	test x\"\$(sed -n -e 4p < file)\" = x4 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7 &&
-	perl -i.bak -p -e 's/^4\$/4444/' file &&
-	perl -i.bak -p -e 's/^7\$/7777/' file &&
+	sed -e 's/^4\$/4444/' \
+	    -e 's/^7\$/7777/' \
+		file >file.munged &&
+	mv file.munged file &&
 	test x\"\$(sed -n -e 4p < file)\" = x4444 &&
 	test x\"\$(sed -n -e 7p < file)\" = x7777 &&
 	git commit -m '4 => 4444, 7 => 7777' file &&

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 12/20] t: refactor tests depending on Perl to print data
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (10 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
                     ` (8 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

A bunch of tests rely on Perl to print data in various different ways.
These usages fall into the following categories:

  - Print data conditionally by matching patterns. These usecases can be
    converted to use awk(1) rather easily.

  - Print data repeatedly. These usecases can typically be converted to
    use a combination of `test-tool genzeros` and sed(1).

  - Print data in reverse. These usecases can be converted to use
    awk(1) or `sort -r`.

Refactor the tests accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0610-reftable-basics.sh          |  7 +++----
 t/t0613-reftable-write-options.sh   |  4 ++--
 t/t1010-mktree.sh                   |  8 ++++----
 t/t4150-am.sh                       | 10 +++++-----
 t/t5300-pack-object.sh              | 16 +++++-----------
 t/t5326-multi-pack-bitmaps.sh       |  6 +++---
 t/t5333-pseudo-merge-bitmaps.sh     | 18 +++++-------------
 t/t5410-receive-pack-alternates.sh  |  6 +++---
 t/t5701-git-serve.sh                |  7 +++++--
 t/t6013-rev-list-reverse-parents.sh | 14 ++++++++------
 t/t6115-rev-list-du.sh              |  8 +-------
 t/t7006-pager.sh                    |  8 ++++----
 t/t8002-blame.sh                    |  2 +-
 t/t9850-shell.sh                    |  4 ++--
 14 files changed, 51 insertions(+), 67 deletions(-)

diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index 5e0a1fa176d..77ed11e7172 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -643,12 +643,11 @@ test_expect_success 'basic: commit and list refs' '
 	test_cmp actual expect
 '
 
-test_expect_success PERL_TEST_HELPERS 'basic: can write large commit message' '
+test_expect_success 'basic: can write large commit message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+
+	awk "BEGIN { for (i = 0; i < 50000; i++) printf \"%s\", \"this is a long commit message\" }" >commit-msg &&
 	git -C repo commit --allow-empty --file=../commit-msg
 '
 
diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh
index fa1e2f9eef8..42aa1592f87 100755
--- a/t/t0613-reftable-write-options.sh
+++ b/t/t0613-reftable-write-options.sh
@@ -139,13 +139,13 @@ test_expect_success 'small block size leads to multiple ref blocks' '
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'small block size fails with large reflog message' '
+test_expect_success 'small block size fails with large reflog message' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
 	(
 		cd repo &&
 		test_commit A &&
-		perl -e "print \"a\" x 500" >logmsg &&
+		test-tool genzeros 500 | tr "\000" "a" >logmsg &&
 		cat >expect <<-EOF &&
 		fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large
 		EOF
diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 4977998e205..e9973f74949 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -41,14 +41,14 @@ test_expect_success 'ls-tree piped to mktree (2)' '
 	test_cmp tree.withsub actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (1)' '
-	perl -e "print reverse <>" <top |
+test_expect_success 'ls-tree output in wrong order given to mktree (1)' '
+	sort -r <top |
 	git mktree >actual &&
 	test_cmp tree actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ls-tree output in wrong order given to mktree (2)' '
-	perl -e "print reverse <>" <top.withsub |
+test_expect_success 'ls-tree output in wrong order given to mktree (2)' '
+	sort -r <top.withsub |
 	git mktree >actual &&
 	test_cmp tree.withsub actual
 '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 4794510d70d..2ae93d3c967 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1073,7 +1073,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
 	test_cmp msg out
 '
 
-test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers' '
+test_expect_success 'am works with multi-line in-body headers' '
 	FORTY="String that has a length of more than forty characters" &&
 	LONG="$FORTY $FORTY" &&
 	rm -fr .git/rebase-apply &&
@@ -1084,13 +1084,13 @@ test_expect_success PERL_TEST_HELPERS 'am works with multi-line in-body headers'
     Body test" --author="$LONG <long@example.com>" &&
 	git format-patch --stdout -1 >patch &&
 	# bump from, date, and subject down to in-body header
-	perl -lpe "
-		if (/^From:/) {
+	awk "
+		/^From:/{
 			print \"From: x <x\@example.com>\";
 			print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
 			print \"Subject: x\n\";
-		}
-	" patch >msg &&
+		}; 1
+	" <patch >msg &&
 	git checkout HEAD^ &&
 	git am msg &&
 	# Ensure that the author and full message are present
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 143856c29f1..a5932b6a8be 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -7,17 +7,11 @@ test_description='git pack-object'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pack-object tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	rm -f .git/index* &&
-	perl -e "print \"a\" x 4096;" >a &&
-	perl -e "print \"b\" x 4096;" >b &&
-	perl -e "print \"c\" x 4096;" >c &&
+	test-tool genzeros 4096 | tr "\000" "a" >a &&
+	test-tool genzeros 4096 | tr "\000" "b" >b &&
+	test-tool genzeros 4096 | tr "\000" "c" >c &&
 	test-tool genrandom "seed a" 2097152 >a_big &&
 	test-tool genrandom "seed b" 2097152 >b_big &&
 	git update-index --add a a_big b b_big c &&
@@ -146,7 +140,7 @@ test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage'
 # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas>
 # e.g.: check_deltas stderr -gt 0
 check_deltas() {
-	deltas=$(perl -lne '/delta (\d+)/ and print $1' "$1") &&
+	deltas=$(sed -n 's/Total [0-9][0-9]* (delta \([0-9][0-9]*\)).*/\1/p' "$1") &&
 	shift &&
 	if ! test "$deltas" "$@"
 	then
@@ -221,7 +215,7 @@ test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '
 	check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
 '
 
-test_expect_success 'compare delta flavors' '
+test_expect_success PERL_TEST_HELPERS 'compare delta flavors' '
 	perl -e '\''
 		defined($_ = -s $_) or die for @ARGV;
 		exit 1 if $ARGV[0] <= $ARGV[1];
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 627f8b4efdc..892aeb09e4b 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -153,7 +153,7 @@ test_midx_bitmap_cases () {
 		)
 	'
 
-	test_expect_success PERL_TEST_HELPERS 'pack.preferBitmapTips' '
+	test_expect_success 'pack.preferBitmapTips' '
 		git init repo &&
 		test_when_finished "rm -fr repo" &&
 		(
@@ -176,8 +176,8 @@ test_midx_bitmap_cases () {
 			comm -13 bitmaps commits >before &&
 			test_line_count = 1 before &&
 
-			perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
-				<before | git update-ref --stdin &&
+			sed "s|\(.*\)|create refs/tags/include/\1 \1|" before |
+			git update-ref --stdin &&
 
 			rm -fr $midx-$(midx_checksum $objdir).bitmap &&
 			rm -fr $midx &&
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 1059ff45fe4..56674db562f 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -6,12 +6,6 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping pseudo-merge bitmap tests; Perl not available'
-	test_done
-fi
-
 test_pseudo_merges () {
 	test-tool bitmap dump-pseudo-merges
 }
@@ -34,9 +28,8 @@ test_pseudo_merges_reused () {
 
 tag_everything () {
 	git rev-list --all --no-object-names >in &&
-	perl -lne '
-		print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/
-	' <in | git update-ref --stdin
+	sed 's|\(.*\)|create refs/tags/\1 \1|' in |
+	git update-ref --stdin
 }
 
 test_expect_success 'setup' '
@@ -108,7 +101,7 @@ test_expect_success 'stale bitmap traversal with pseudo-merges' '
 	test_cmp expect actual
 '
 
-test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
+test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
 	test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
 	test_config bitmapPseudoMerge.test.maxMerges 1 &&
 	test_config bitmapPseudoMerge.test.stableThreshold never &&
@@ -241,8 +234,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 			test_commit_bulk 16 &&
 
 			git rev-list HEAD~16.. >in &&
-
-			perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in |
+			sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" in |
 			git update-ref --stdin || return 1
 		done &&
 
@@ -258,7 +250,7 @@ test_expect_success 'pseudo-merge pattern with capture groups' '
 		do
 			test_pseudo_merge_commits $m >oids &&
 			grep -f oids refs |
-			perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" |
+			sed -n "s|refs/remotes/\([0-9][0-9]*\)/|\1|p" &&
 			sort -u || return 1
 		done >remotes &&
 
diff --git a/t/t5410-receive-pack-alternates.sh b/t/t5410-receive-pack-alternates.sh
index 6a009fdcd71..4e82fd102e3 100755
--- a/t/t5410-receive-pack-alternates.sh
+++ b/t/t5410-receive-pack-alternates.sh
@@ -17,10 +17,10 @@ test_expect_success 'setup' '
 '
 
 extract_haves () {
-	depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+	depacketize | sed -n 's/^\([^ ][^ ]*\) \.have/\1/p'
 }
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
+test_expect_success 'with core.alternateRefsCommand' '
 	write_script fork/alternate-refs <<-\EOF &&
 		git --git-dir="$1" for-each-ref \
 			--format="%(objectname)" \
@@ -33,7 +33,7 @@ test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsCommand' '
 	test_cmp expect actual.haves
 '
 
-test_expect_success PERL_TEST_HELPERS 'with core.alternateRefsPrefixes' '
+test_expect_success 'with core.alternateRefsPrefixes' '
 	test_config -C fork core.alternateRefsPrefixes "refs/heads/private" &&
 	git rev-parse private/branch >expect &&
 	printf "0000" | git receive-pack fork >actual &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 200bf06ecb3..d4c28bae39e 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -220,7 +220,7 @@ test_expect_success 'refs/heads prefix' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
+test_expect_success 'ignore very large set of prefixes' '
 	# generate a large number of ref-prefixes that we expect
 	# to match nothing; the value here exceeds TOO_MANY_PREFIXES
 	# from ls-refs.c.
@@ -228,7 +228,10 @@ test_expect_success PERL_TEST_HELPERS 'ignore very large set of prefixes' '
 		echo command=ls-refs &&
 		echo object-format=$(test_oid algo) &&
 		echo 0001 &&
-		perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" &&
+		awk "{
+			for (i = 1; i <= 65536; i++)
+				print \"ref-prefix refs/heads/\", \$i
+		}" &&
 		echo 0000
 	} |
 	test-tool pkt-line pack >in &&
diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh
index 8074185742c..273196f52b5 100755
--- a/t/t6013-rev-list-reverse-parents.sh
+++ b/t/t6013-rev-list-reverse-parents.sh
@@ -26,17 +26,19 @@ test_expect_success 'set up --reverse example' '
 	commit five
 	'
 
-test_expect_success PERL_TEST_HELPERS '--reverse --parents --full-history combines correctly' '
-	git rev-list --parents --full-history main -- foo |
-		perl -e "print reverse <>" > expected &&
+reverse () {
+	awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'
+}
+
+test_expect_success '--reverse --parents --full-history combines correctly' '
+	git rev-list --parents --full-history main -- foo | reverse >expected &&
 	git rev-list --reverse --parents --full-history main -- foo \
 		> actual &&
 	test_cmp expected actual
 	'
 
-test_expect_success PERL_TEST_HELPERS '--boundary does too' '
-	git rev-list --boundary --parents --full-history main ^root -- foo |
-		perl -e "print reverse <>" > expected &&
+test_expect_success '--boundary does too' '
+	git rev-list --boundary --parents --full-history main ^root -- foo | reverse >expected &&
 	git rev-list --boundary --reverse --parents --full-history \
 		main ^root -- foo > actual &&
 	test_cmp expected actual
diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh
index 6a74be576a2..04c577dad69 100755
--- a/t/t6115-rev-list-du.sh
+++ b/t/t6115-rev-list-du.sh
@@ -4,12 +4,6 @@ test_description='basic tests of rev-list --disk-usage'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list disk usage tests; Perl not available'
-	test_done
-fi
-
 # we want a mix of reachable and unreachable, as well as
 # objects in the bitmapped pack and some outside of it
 test_expect_success 'set up repository' '
@@ -28,7 +22,7 @@ test_expect_success 'set up repository' '
 disk_usage_slow () {
 	git rev-list --no-object-names "$@" |
 	git cat-file --batch-check="%(objectsize:disk)" |
-	perl -lne '$total += $_; END { print $total}'
+	awk '{ i += $1 } END { print i }'
 }
 
 # check behavior with given rev-list options; note that
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 49aae183829..9717e825f0d 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -661,10 +661,10 @@ test_expect_success 'setup trace2' '
 	export GIT_TRACE2_BRIEF
 '
 
-test_expect_success PERL_TEST_HELPERS 'setup large log output' '
-	perl -e "
-		print \"this is a long commit message\" x 50000
-	" >commit-msg &&
+test_expect_success 'setup large log output' '
+	test-tool genzeros 50000 |
+	tr "\000" "a" |
+	sed "s/a/this is a long commit message/g" >commit-msg &&
 	git commit --allow-empty -F commit-msg
 '
 
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index b40199df231..7822947f028 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -107,7 +107,7 @@ test_expect_success 'set up abbrev tests' '
 		expect=$1 && shift &&
 		echo $sha1 | cut -c 1-$expect >expect &&
 		git blame "$@" abbrev.t >actual &&
-		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
+		sed -n "s/^[\^]\{0,1\}\([0-9a-f][0-9a-f]*\).*/\1/p" actual >actual.sha &&
 		test_cmp expect actual.sha
 	}
 '
diff --git a/t/t9850-shell.sh b/t/t9850-shell.sh
index f619b60f226..21c3af48bd0 100755
--- a/t/t9850-shell.sh
+++ b/t/t9850-shell.sh
@@ -29,8 +29,8 @@ test_expect_success 'shell allows interactive command' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'shell complains of overlong commands' '
-	perl -e "print \"a\" x 2**12 for (0..2**19)" |
+test_expect_success 'shell complains of overlong commands' '
+	test-tool genzeros | tr "\000" "a" |
 	test_must_fail git shell 2>err &&
 	grep "too long" err
 '

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 13/20] t: refactor tests depending on Perl for textconv scripts
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (11 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
                     ` (7 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We have a couple of tests that depend on Perl for textconv scripts.
Refactor these tests to instead be implemented via shell utilities so
that we can drop a couple of PERL_TEST_HELPERS prerequisites.

Note that the conversion in t4030 is not a one-to-one equivalent to the
previous textconv script. Before this change we used to essentially do a
hexdump via Perl. The obvious conversion here would be to use `test-tool
hexdump` like we do for the other tests. But this would lead to a ripple
effect where we would have to adapt a bunch of other tests with a bunch
of seemingly unrelated changes, which would be somewhat awkward.

Instead, we're going with the minimum viable change: the test files we
write contain "\001" and "\000", and the test's expectation is that
those get translated into proper ASCII characters. So instead of doing a
full hexdump, we simply use tr(1) to translate these specific bytes.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t4030-diff-textconv.sh       | 15 +++------------
 t/t4031-diff-rewrite-binary.sh | 19 +++++++------------
 t/t7815-grep-binary.sh         | 15 +++------------
 3 files changed, 13 insertions(+), 36 deletions(-)

diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index c7d8eb12453..f904fc19f69 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -4,12 +4,6 @@ test_description='diff.*.textconv tests'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping diff textconv tests; Perl not available'
-	test_done
-fi
-
 find_diff() {
 	sed '1,/^index /d' | sed '/^-- $/,$d'
 }
@@ -26,13 +20,10 @@ cat >expect.text <<'EOF'
 +1
 EOF
 
-cat >hexdump <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-chmod +x hexdump
-
 test_expect_success 'setup binary file with history' '
+	write_script hexdump <<-\EOF &&
+	tr "\000\001" "01" <"$1"
+	EOF
 	test_commit --printf one file "\\0\\n" &&
 	test_commit --printf --append two file "\\01\\n"
 '
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index cbe50b15772..15e012ccc7c 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -57,24 +57,19 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' '
 	grep " rewrite file" diff
 '
 
-{
-	echo "#!$SHELL_PATH"
-	cat <<'EOF'
-"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1"
-EOF
-} >dump
-chmod +x dump
-
 test_expect_success 'setup textconv' '
+	write_script dump <<-\EOF &&
+	test-tool hexdump <"$1"
+	EOF
 	echo file diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/dump
 '
 
-test_expect_success PERL_TEST_HELPERS 'rewrite diff respects textconv' '
+test_expect_success 'rewrite diff respects textconv' '
 	git diff -B >diff &&
-	grep "dissimilarity index" diff &&
-	grep "^-61" diff &&
-	grep "^-0" diff
+	test_grep "dissimilarity index" diff &&
+	test_grep "^-3d 0a 00" diff &&
+	test_grep "^+3d 0a 01" diff
 '
 
 test_done
diff --git a/t/t7815-grep-binary.sh b/t/t7815-grep-binary.sh
index b2730d200c8..3bd91da9707 100755
--- a/t/t7815-grep-binary.sh
+++ b/t/t7815-grep-binary.sh
@@ -4,12 +4,6 @@ test_description='git grep in binary files'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping grep binary tests; Perl not available'
-	test_done
-fi
-
 test_expect_success 'setup' "
 	echo 'binaryQfileQm[*]cQ*æQð' | q_to_nul >a &&
 	git add a &&
@@ -120,13 +114,10 @@ test_expect_success 'grep respects not-binary diff attribute' '
 	test_cmp expect actual
 '
 
-cat >nul_to_q_textconv <<'EOF'
-#!/bin/sh
-"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
-EOF
-chmod +x nul_to_q_textconv
-
 test_expect_success 'setup textconv filters' '
+	write_script nul_to_q_textconv <<-\EOF &&
+	tr "\000" "Q" <"$1"
+	EOF
 	echo a diff=foo >.gitattributes &&
 	git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
 '

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (12 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
                     ` (6 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `sanitize_pgp()` test helper uses Perl to strip PGP signatures from
stdin. Refactor it to instead use sed(1) so that we drop the
PERL_TEST_HELPERS prerequisite in users of this library.

Note that we have to add PERL_TEST_HELPERS to a subset of tests in t6300
now that the test suite doesn't bail out early anymore in case the
prerequisite isn't set.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-gpg.sh            |  6 +-----
 t/t6300-for-each-ref.sh | 21 ++++++++++-----------
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index 3845b6ac449..937b876bd05 100644
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -192,9 +192,5 @@ test_lazy_prereq GPGSSH_VERIFYTIME '
 '
 
 sanitize_pgp() {
-	perl -ne '
-		/^-----END PGP/ and $in_pgp = 0;
-		print unless $in_pgp;
-		/^-----BEGIN PGP/ and $in_pgp = 1;
-	'
+	sed "/^-----BEGIN PGP/,/^-----END PGP/{/^-/p;d;}"
 }
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 732a4d3171e..5db7038c417 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -10,12 +10,6 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping for-each-ref tests; Perl not available'
-	test_done
-fi
-
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
 setdate_and_increment () {
@@ -1215,7 +1209,7 @@ test_expect_success '%(raw) with --tcl must fail' '
 	test_must_fail git for-each-ref --format="%(raw)" --tcl
 '
 
-test_expect_success '%(raw) with --perl' '
+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
 	git for-each-ref --format="\$name= %(raw);
 print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
 	cmp blob1 actual &&
@@ -1442,9 +1436,14 @@ test_expect_success 'set up trailers for next test' '
 '
 
 test_trailer_option () {
+	if test "$#" -eq 3
+	then
+		prereq="$1"
+		shift
+	fi &&
 	title=$1 option=$2
 	cat >expect
-	test_expect_success "$title" '
+	test_expect_success $prereq "$title" '
 		git for-each-ref --format="%($option)" refs/heads/main >actual &&
 		test_cmp expect actual &&
 		git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
@@ -1452,7 +1451,7 @@ test_trailer_option () {
 	'
 }
 
-test_trailer_option '%(trailers:unfold) unfolds trailers' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
 	'trailers:unfold' <<-EOF
 	$(unfold <trailers)
 
@@ -1482,13 +1481,13 @@ test_trailer_option '%(trailers:only=no) shows all trailers' \
 
 	EOF
 
-test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
 	'trailers:only,unfold' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 
 	EOF
 
-test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
 	'trailers:unfold,only' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
 

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 15/20] t/lib-t6000: refactor `name_from_description()` to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (13 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
                     ` (5 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `name_from_description()` test helper uses Perl to munge a given
description and convert it into a name. Refactor it to instead use a
combination of sed(1) and tr(1) so that we drop PERL_TEST_HELPERS
prerequisites in users of this library.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-t6000.sh                 | 13 ++++++-------
 t/t6002-rev-list-bisect.sh     |  6 ------
 t/t6003-rev-list-topo-order.sh |  6 ------
 3 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
index fba6778ca35..35c54724650 100644
--- a/t/lib-t6000.sh
+++ b/t/lib-t6000.sh
@@ -109,13 +109,12 @@ check_output () {
 # All alphanums translated into -'s which are then compressed and stripped
 # from front and back.
 name_from_description () {
-	perl -pe '
-		s/[^A-Za-z0-9.]/-/g;
-		s/-+/-/g;
-		s/-$//;
-		s/^-//;
-		y/A-Z/a-z/;
-	'
+	sed \
+		-e 's/[^A-Za-z0-9.]/-/g' \
+		-e 's/--*/-/g' \
+		-e 's/-$//' \
+		-e 's/^-//' \
+		-e 'y/A-Z/a-z/'
 }
 
 
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index 5e1482aff78..daa009c9a1b 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -7,12 +7,6 @@ test_description='Tests git rev-list --bisect functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list bisect tests; Perl not available'
-	test_done
-fi
-
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
 # e.g. test_bisection 1 --bisect l1 ^l0
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 02dd4127aff..0d7055d46d4 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -8,12 +8,6 @@ test_description='Tests git rev-list --topo-order functionality'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping rev-list topo-order tests; Perl not available'
-	test_done
-fi
-
 list_duplicates()
 {
     "$@" | sort | uniq -d

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 16/20] t/lib-httpd: refactor "one-time-perl" CGI script to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (14 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
                     ` (4 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

Our Apache HTTPD setup exposes an "one_time_perl" endpoint to access
repositories. If used, we execute the "apply-one-time-perl.sh" CGI
script that checks whether we have a "one-time-perl" script. If so, that
script gets executed so that it can munge what would be served. Once
done, the script gets removed so that it doesn't execute a second time.

As the name says, this functionality expects the user to pass a Perl
script. This isn't really necessary though: we can just as easily
implement the same thing with arbitrary scripts.

Refactor the code so that we instead expect an arbitrary script to
exist and rename the functionality to "one-time-script". Adapt callers
to use shell utilities instead of Perl so that we can drop the
PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/lib-httpd.sh                       |  2 +-
 t/lib-httpd/apache.conf              |  6 ++---
 t/lib-httpd/apply-one-time-perl.sh   | 27 --------------------
 t/lib-httpd/apply-one-time-script.sh | 26 +++++++++++++++++++
 t/t5537-fetch-shallow.sh             | 17 ++++++-------
 t/t5616-partial-clone.sh             | 48 +++++++++++++++++++-----------------
 t/t5702-protocol-v2.sh               | 27 +++++++++++---------
 t/t5703-upload-pack-ref-in-want.sh   | 10 +++++---
 8 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index d83bafeab32..5091db949b7 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -165,7 +165,7 @@ prepare_httpd() {
 	install_script broken-smart-http.sh
 	install_script error-smart-http.sh
 	install_script error.sh
-	install_script apply-one-time-perl.sh
+	install_script apply-one-time-script.sh
 	install_script nph-custom-auth.sh
 
 	ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 022276a6b9a..e631ab0eb5e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -135,7 +135,7 @@ SetEnv PERL_PATH ${PERL_PATH}
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
-<LocationMatch /one_time_perl/>
+<LocationMatch /one_time_script/>
 	SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
 	SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
@@ -159,7 +159,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
-ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
+ScriptAliasMatch /one_time_script/(.*) apply-one-time-script.sh/$1
 ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Directory ${GIT_EXEC_PATH}>
 	Options FollowSymlinks
@@ -182,7 +182,7 @@ ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1
 <Files error.sh>
   Options ExecCGI
 </Files>
-<Files apply-one-time-perl.sh>
+<Files apply-one-time-script.sh>
 	Options ExecCGI
 </Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
deleted file mode 100644
index d7f9fed6aee..00000000000
--- a/t/lib-httpd/apply-one-time-perl.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# If "one-time-perl" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,
-# using the contents of "one-time-perl" as the perl command to be run. If the
-# response was modified as a result, delete "one-time-perl" so that subsequent
-# HTTP responses are no longer modified.
-#
-# This can be used to simulate the effects of the repository changing in
-# between HTTP request-response pairs.
-if test -f one-time-perl
-then
-	LC_ALL=C
-	export LC_ALL
-
-	"$GIT_EXEC_PATH/git-http-backend" >out
-	"$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified
-
-	if cmp -s out out_modified
-	then
-		cat out
-	else
-		cat out_modified
-		rm one-time-perl
-	fi
-else
-	"$GIT_EXEC_PATH/git-http-backend"
-fi
diff --git a/t/lib-httpd/apply-one-time-script.sh b/t/lib-httpd/apply-one-time-script.sh
new file mode 100644
index 00000000000..b1682944e28
--- /dev/null
+++ b/t/lib-httpd/apply-one-time-script.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# If "one-time-script" exists in $HTTPD_ROOT_PATH, run the script on the HTTP
+# response. If the response was modified as a result, delete "one-time-script"
+# so that subsequent HTTP responses are no longer modified.
+#
+# This can be used to simulate the effects of the repository changing in
+# between HTTP request-response pairs.
+if test -f one-time-script
+then
+	LC_ALL=C
+	export LC_ALL
+
+	"$GIT_EXEC_PATH/git-http-backend" >out
+	./one-time-script out >out_modified
+
+	if cmp -s out out_modified
+	then
+		cat out
+	else
+		cat out_modified
+		rm one-time-script
+	fi
+else
+	"$GIT_EXEC_PATH/git-http-backend"
+fi
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 77d20d19110..6588ce62264 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -256,7 +256,7 @@ start_httpd
 
 REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 
-test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before writing shallow file' '
+test_expect_success 'shallow fetches check connectivity before writing shallow file' '
 	rm -rf "$REPO" client &&
 
 	git init "$REPO" &&
@@ -271,22 +271,21 @@ test_expect_success PERL_TEST_HELPERS 'shallow fetches check connectivity before
 	git -C "$REPO" config protocol.version 2 &&
 	git -C client config protocol.version 2 &&
 
-	git -C client fetch --depth=2 "$HTTPD_URL/one_time_perl/repo" main:a_branch &&
+	git -C client fetch --depth=2 "$HTTPD_URL/one_time_script/repo" main:a_branch &&
 
 	# Craft a situation in which the server sends back an unshallow request
 	# with an empty packfile. This is done by refetching with a shorter
 	# depth (to ensure that the packfile is empty), and overwriting the
 	# shallow line in the response with the unshallow line we want.
-	printf "$(test_oid perl)" \
-	       "$(git -C "$REPO" rev-parse HEAD)" \
-	       "$(git -C "$REPO" rev-parse HEAD^)" \
-	       >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF &&
+	sed "$(printf "$(test_oid perl)" "$(git -C "$REPO" rev-parse HEAD)" "$(git -C "$REPO" rev-parse HEAD^)")" "\$1"
+	EOF
 	test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
-		fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
+		fetch --depth=1 "$HTTPD_URL/one_time_script/repo" \
 		main:a_branch &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl" &&
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script" &&
 
 	# Ensure that the resulting repo is consistent, despite our failure to
 	# fetch.
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index bc7e0fec8dc..1e354e057fa 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -737,21 +737,25 @@ intersperse () {
 	sed 's/\(..\)/'$1'\1/g'
 }
 
-# Create a one-time-perl command to replace the existing packfile with $1.
+# Create a one-time-script command to replace the existing packfile with $1.
 replace_packfile () {
-	# The protocol requires that the packfile be sent in sideband 1, hence
-	# the extra \x01 byte at the beginning.
-	cp $1 "$HTTPD_ROOT_PATH/one-time-pack" &&
-	echo 'if (/packfile/) {
-		print;
-		my $length = -s "one-time-pack";
-		printf "%04x\x01", $length + 5;
-		print `cat one-time-pack` . "0000";
-		last
-	}' >"$HTTPD_ROOT_PATH/one-time-perl"
+	cp "$1" one-time-pack &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	if grep packfile "\$1" >/dev/null
+	then
+		sed '/packfile/q' "\$1" &&
+		# The protocol requires that the packfile be sent in sideband
+		# 1, hence the extra \001 byte at the beginning.
+		printf "%04x\001" \$((\$(wc -c <"$PWD/one-time-pack") + 5)) &&
+		cat "$PWD/one-time-pack" &&
+		printf "0000"
+	else
+		cat "\$1"
+	fi
+	EOF
 }
 
-test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point to objects' '
+test_expect_success 'upon cloning, check that all refs point to objects' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -776,15 +780,15 @@ test_expect_success PERL_TEST_HELPERS 'upon cloning, check that all refs point t
 	# section header.
 	test_config -C "$SERVER" protocol.version 2 &&
 	test_must_fail git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2>err &&
 
 	test_grep "did not send all necessary objects" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
-test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not sending target of tag' '
+test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
 	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
 	rm -rf "$SERVER" repo &&
 	test_create_repo "$SERVER" &&
@@ -818,11 +822,11 @@ test_expect_success PERL_TEST_HELPERS 'when partial cloning, tolerate server not
 
 	# Exercise to make sure it works.
 	git -c protocol.version=2 clone \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo 2> err &&
 	! grep "missing object referenced by" err &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against missing promisor objects' '
@@ -845,7 +849,7 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 
 	# Clone. The client has deltabase_have but not deltabase_missing.
 	git -c protocol.version=2 clone --no-checkout \
-		--filter=blob:none $HTTPD_URL/one_time_perl/server repo &&
+		--filter=blob:none $HTTPD_URL/one_time_script/server repo &&
 	git -C repo hash-object -w -- "$SERVER/have.txt" &&
 
 	# Sanity check to ensure that the client does not have
@@ -899,8 +903,8 @@ test_expect_success PERL_TEST_HELPERS 'tolerate server sending REF_DELTA against
 	grep "want $(cat deltabase_missing)" trace &&
 	! grep "want $(cat deltabase_have)" trace &&
 
-	# Ensure that the one-time-perl script was used.
-	! test -e "$HTTPD_ROOT_PATH/one-time-perl"
+	# Ensure that the one-time-script script was used.
+	! test -e "$HTTPD_ROOT_PATH/one-time-script"
 '
 
 # DO NOT add non-httpd-specific tests here, because the last part of this
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ad5e772cd72..8548854f32e 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1120,7 +1120,7 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
 	! grep "git< version 2" log
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM' '
+test_expect_success 'when server sends "ready", expect DELIM' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1132,15 +1132,16 @@ test_expect_success PERL_TEST_HELPERS 'when server sends "ready", expect DELIM'
 
 	# After "ready" in the acknowledgments section, pretend that a FLUSH
 	# (0000) was sent instead of a DELIM (0001).
-	printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/ready/{n;s/0001/0000/;}" "$1"
+	EOF
 
 	test_must_fail git -C http_child -c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	test_grep "expected packfile to be sent after .ready." err
 '
 
-test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect FLUSH' '
+test_expect_success 'when server does not send "ready", expect FLUSH' '
 	rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
 
 	git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
@@ -1157,12 +1158,13 @@ test_expect_success PERL_TEST_HELPERS 'when server does not send "ready", expect
 
 	# After the acknowledgments section, pretend that a DELIM
 	# (0001) was sent instead of a FLUSH (0000).
-	printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "/acknowledgments/,//{s/0000/0001/;}" "$1"
+	EOF
 
 	test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
 		-c protocol.version=2 \
-		fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
+		fetch "$HTTPD_URL/one_time_script/http_parent" 2> err &&
 	grep "fetch< .*acknowledgments" log &&
 	! grep "fetch< .*ready" log &&
 	test_grep "expected no other sections to be sent after no .ready." err
@@ -1446,14 +1448,15 @@ test_expect_success 'http:// --negotiate-only' '
 	grep "$COMMON" out
 '
 
-test_expect_success PERL_TEST_HELPERS 'http:// --negotiate-only without wait-for-done support' '
+test_expect_success 'http:// --negotiate-only without wait-for-done support' '
 	SERVER="server" &&
-	URI="$HTTPD_URL/one_time_perl/server" &&
+	URI="$HTTPD_URL/one_time_script/server" &&
 
 	setup_negotiate_only "$SERVER" "$URI" &&
 
-	echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \
-		>"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/ wait-for-done/ xxxx-xxx-xxxx/" "$1"
+	EOF
 
 	test_must_fail git -c protocol.version=2 -C client fetch \
 		--no-tags \
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index f59d47aa6c6..fc915e7b823 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -468,7 +468,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '
 		test_commit m3 &&
 		git tag -d m2 m3
 	) &&
-	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo" &&
+	git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_script/repo" &&
 	git -C "$LOCAL_PRISTINE" config protocol.version 2
 '
 
@@ -481,7 +481,9 @@ inconsistency () {
 	# RPCs during a single negotiation.
 	oid1=$(git -C "$REPO" rev-parse $1) &&
 	oid2=$(git -C "$REPO" rev-parse $2) &&
-	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-EOF
+	sed "s/$oid1/$oid2/" "\$1"
+	EOF
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
@@ -533,7 +535,9 @@ test_expect_success 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
-	echo "s/main/rain/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
+	write_script "$HTTPD_ROOT_PATH/one-time-script" <<-\EOF &&
+	sed "s/main/rain/" "$1"
+	EOF
 	test_must_fail git -C local fetch 2>err &&
 
 	test_grep "fatal: remote error: unknown ref refs/heads/rain" err

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 17/20] t0021: refactor `generate_random_characters()` to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (15 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
                     ` (3 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `generate_random_characters()` helper function generates N
random characters in the range 'a-z' and writes them into a file. The
logic currently uses Perl, but it can be adapted rather easily by:

  - Making `test-tool genrandom` generate an infinite stream.

  - Using `tr -dc` to strip all characters which aren't in the range of
    'a-z'.

  - Using `test_copy_bytes()` to copy the first N bytes.

This allows us to drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0021-conversion.sh | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 4a892a91780..bf10d253ec4 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -20,8 +20,7 @@ EOF
 generate_random_characters () {
 	LEN=$1
 	NAME=$2
-	test-tool genrandom some-seed $LEN |
-		perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
+	test-tool genrandom some-seed | tr -dc 'a-z' | test_copy_bytes "$LEN" >"$TEST_ROOT/$NAME"
 }
 
 filter_git () {
@@ -619,7 +618,7 @@ test_expect_success 'required process filter should be used only for "clean" ope
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter should process multiple packets' '
+test_expect_success 'required process filter should process multiple packets' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 
@@ -684,7 +683,7 @@ test_expect_success PERL_TEST_HELPERS 'required process filter should process mu
 	)
 '
 
-test_expect_success PERL_TEST_HELPERS 'required process filter with clean error should fail' '
+test_expect_success 'required process filter with clean error should fail' '
 	test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
 	test_config_global filter.protocol.required true &&
 	rm -rf repo &&

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 18/20] t0210: refactor trace2 scrubbing to not use Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (16 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
                     ` (2 subsequent siblings)
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The output generated by our trace2 mechanism contains several fields
that are dependent on the environment they're being run in, which makes
it somewhat harder to test it. As a countermeasure we scrub the output
and strip out any fields that contain such information.

The logic to do so is implemented in Perl, but it can be trivially
ported to instead use sed(1). Refactor the code accordingly so that we
can drop the PERL_TEST_HELPERS prerequisite.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t0210-trace2-normal.sh  | 61 +++++++++++++++++++++++++++++++++--------------
 t/t0210/scrub_normal.perl | 54 -----------------------------------------
 2 files changed, 43 insertions(+), 72 deletions(-)

diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index ba4c0442b85..96c68f65df2 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -4,12 +4,6 @@ test_description='test trace2 facility (normal target)'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping trace2 tests; Perl not available'
-	test_done
-fi
-
 # Turn off any inherited trace2 settings for this test.
 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
 sane_unset GIT_TRACE2_BRIEF
@@ -59,10 +53,41 @@ GIT_TRACE2_BRIEF=1 && export GIT_TRACE2_BRIEF
 #
 # Implicit return from cmd_<verb> function propagates <code>.
 
+scrub_normal () {
+	# Scrub the variable fields from the normal trace2 output to make
+	# testing easier:
+	#
+	#   1. Various messages include an elapsed time in the middle of the
+	#      message. Replace the time with a placeholder to simplify our
+	#      HEREDOC in the test script.
+	#
+	#   2. We expect:
+	#
+	#        start <argv0> [<argv1> [<argv2> [...]]]
+	#
+	#      where argv0 might be a relative or absolute path, with or
+	#      without quotes, and platform dependent. Replace argv0 with a
+	#      token for HEREDOC matching in the test script.
+	#
+	#   3. Likewise, the 'cmd_path' message breaks out argv[0].
+	#
+	#      This line is only emitted when RUNTIME_PREFIX is defined,
+	#      so just omit it for testing purposes.
+	#
+	#   4. 'cmd_ancestry' is not implemented everywhere, so for portability's
+	#      sake, skip it when parsing normal.
+	sed \
+		-e 's/elapsed:[0-9]*\.[0-9][0-9]*\([eE][-+]\{0,1\}[0-9][0-9]*\)\{0,1\}/elapsed:_TIME_/g' \
+		-e "s/^start '[^']*' \(.*\)/start _EXE_ \1/" \
+		-e 's/^start [^ ][^ ]* \(.*\)/start _EXE_ \1/' \
+		-e '/^cmd_path/d' \
+		-e '/^cmd_ancestry/d'
+}
+
 test_expect_success 'normal stream, return code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -76,7 +101,7 @@ test_expect_success 'normal stream, return code 0' '
 test_expect_success 'normal stream, return code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 001return 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 1
@@ -91,7 +116,7 @@ test_expect_success 'automatic filename' '
 	test_when_finished "rm -r traces actual expect" &&
 	mkdir traces &&
 	GIT_TRACE2="$(pwd)/traces" test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <"$(ls traces/*)" >actual &&
+	scrub_normal <"$(ls traces/*)" >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -109,7 +134,7 @@ test_expect_success 'automatic filename' '
 test_expect_success 'normal stream, exit code 0' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 0
@@ -123,7 +148,7 @@ test_expect_success 'normal stream, exit code 0' '
 test_expect_success 'normal stream, exit code 1' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 002exit 1 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 002exit 1
@@ -141,7 +166,7 @@ test_expect_success 'normal stream, exit code 1' '
 test_expect_success 'normal stream, error event' '
 	test_when_finished "rm trace.normal actual expect" &&
 	GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\''
@@ -161,7 +186,7 @@ test_expect_success 'normal stream, error event' '
 test_expect_success 'BUG messages are written to trace2' '
 	test_when_finished "rm trace.normal actual expect" &&
 	test_must_fail env GIT_TRACE2="$(pwd)/trace.normal" test-tool trace2 007bug &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 007bug
@@ -185,7 +210,7 @@ test_expect_success 'bug messages with BUG_if_bug() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 008bug
@@ -211,7 +236,7 @@ test_expect_success 'bug messages without explicit BUG_if_bug() are written to t
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 009bug_BUG
@@ -236,7 +261,7 @@ test_expect_success 'bug messages followed by BUG() are written to trace2' '
 	sed "s/^.*: //" <err >actual &&
 	test_cmp expect actual &&
 
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 010bug_BUG
@@ -268,7 +293,7 @@ test_expect_success 'using global config, normal stream, return code 0' '
 	test_config_global trace2.normalBrief 1 &&
 	test_config_global trace2.normalTarget "$(pwd)/trace.normal" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
@@ -286,7 +311,7 @@ test_expect_success 'using global config with include' '
 	mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" &&
 	test_config_global include.path "$(pwd)/real.gitconfig" &&
 	test-tool trace2 001return 0 &&
-	perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual &&
+	scrub_normal <trace.normal >actual &&
 	cat >expect <<-EOF &&
 		version $V
 		start _EXE_ trace2 001return 0
diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl
deleted file mode 100644
index 7cc4de392a0..00000000000
--- a/t/t0210/scrub_normal.perl
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/perl
-#
-# Scrub the variable fields from the normal trace2 output to
-# make testing easier.
-
-use strict;
-use warnings;
-
-my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?';
-
-# This code assumes that the trace2 data was written with bare
-# turned on (which omits the "<clock> <file>:<line>" prefix.
-
-while (<>) {
-    # Various messages include an elapsed time in the middle
-    # of the message.  Replace the time with a placeholder to
-    # simplify our HEREDOC in the test script.
-    s/elapsed:$float/elapsed:_TIME_/g;
-
-    my $line = $_;
-
-    # we expect:
-    #    start <argv0> [<argv1> [<argv2> [...]]]
-    #
-    # where argv0 might be a relative or absolute path, with
-    # or without quotes, and platform dependent.  Replace argv0
-    # with a token for HEREDOC matching in the test script.
-
-    if ($line =~ m/^start/) {
-	$line =~ /^start\s+(.*)/;
-	my $argv = $1;
-	$argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/;
-	my $argv_0 = $1;
-	my $argv_rest = $2;
-
-	print "start _EXE_ $argv_rest\n";
-    }
-    elsif ($line =~ m/^cmd_path/) {
-	# Likewise, the 'cmd_path' message breaks out argv[0].
-	#
-	# This line is only emitted when RUNTIME_PREFIX is defined,
-	# so just omit it for testing purposes.
-	# print "cmd_path _EXE_\n";
-    }
-    elsif ($line =~ m/^cmd_ancestry/) {
-	# 'cmd_ancestry' is not implemented everywhere, so for portability's
-	# sake, skip it when parsing normal.
-	#
-	# print "$line";
-    }
-    else {
-	print "$line";
-    }
-}

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 19/20] t5316: refactor `max_chain()` to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (17 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03  5:06   ` [PATCH v4 20/20] t5703: refactor test " Patrick Steinhardt
  2025-04-03 12:12   ` [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite Johannes Schindelin
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

The `max_chain()` helper function is used to extract the maximum delta
chain of a packfile as printed by git-index-pack(1). The script uses
Perl to extract that data, but it can be trivially refactored to use
awk(1) instead.

Refactor the helper accordingly so that we can drop a couple of
PERL_TEST_HELPERS prerequisites.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5316-pack-delta-depth.sh | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index cd947b5a5ef..defaa06d650 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -76,18 +76,18 @@ test_expect_success 'create series of packs' '
 
 max_chain() {
 	git index-pack --verify-stat-only "$1" >output &&
-	perl -lne '
-	  BEGIN { $len = 0 }
-	  /chain length = (\d+)/ and $len = $1;
-	  END { print $len }
-	' output
+	awk '
+		BEGIN { len=0 }
+		/chain length = [0-9]+:/{ len=$4 }
+		END { print len }
+	' <output | tr -d ':'
 }
 
 # Note that this whole setup is pretty reliant on the current
 # packing heuristics. We double-check that our test case
 # actually produces a long chain. If it doesn't, it should be
 # adjusted (or scrapped if the heuristics have become too unreliable)
-test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
+test_expect_success 'packing produces a long delta' '
 	# Use --window=0 to make sure we are seeing reused deltas,
 	# not computing a new long chain.
 	pack=$(git pack-objects --all --window=0 </dev/null pack) &&
@@ -96,21 +96,21 @@ test_expect_success PERL_TEST_HELPERS 'packing produces a long delta' '
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth limits depth' '
+test_expect_success '--depth limits depth' '
 	pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
 	echo 5 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS '--depth=0 disables deltas' '
+test_expect_success '--depth=0 disables deltas' '
 	pack=$(git pack-objects --all --depth=0 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success PERL_TEST_HELPERS 'negative depth disables deltas' '
+test_expect_success 'negative depth disables deltas' '
 	pack=$(git pack-objects --all --depth=-1 </dev/null pack) &&
 	echo 0 >expect &&
 	max_chain pack-$pack.pack >actual &&

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v4 20/20] t5703: refactor test to not depend on Perl
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (18 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
@ 2025-04-03  5:06   ` Patrick Steinhardt
  2025-04-03 12:12   ` [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite Johannes Schindelin
  20 siblings, 0 replies; 121+ messages in thread
From: Patrick Steinhardt @ 2025-04-03  5:06 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Eric Sunshine, Karthik Nayak, Phillip Wood

We use Perl due to two different reasons in t5703:

  - To filter advertised capabilities.

  - To set up a CGI script with HTTPD.

Refactor the first category to use `test_grep` instead. Refactoring the
second category would be a bit more involved, so instead we add the
PERL_TEST_HELPERS prerequisite to those individual tests now.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t5703-upload-pack-ref-in-want.sh | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index fc915e7b823..249137b4673 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -4,12 +4,6 @@ test_description='upload-pack ref-in-want'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PERL_TEST_HELPERS
-then
-	skip_all='skipping upload-pack ref-in-want tests; Perl not available'
-	test_done
-fi
-
 get_actual_refs () {
 	sed -n -e '/wanted-refs/,/0001/{
 		/wanted-refs/d
@@ -89,18 +83,15 @@ test_expect_success 'setup repository' '
 
 test_expect_success 'config controls ref-in-want advertisement' '
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant false &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_must_be_empty out.filter &&
+	test_grep ! "ref-in-want" out &&
 
 	git config uploadpack.allowRefInWant true &&
 	test-tool serve-v2 --advertise-capabilities >out &&
-	perl -ne "/ref-in-want/ and print" out >out.filter &&
-	test_file_not_empty out.filter
+	test_grep "ref-in-want" out
 '
 
 test_expect_success 'invalid want-ref line' '
@@ -486,7 +477,7 @@ inconsistency () {
 	EOF
 }
 
-test_expect_success 'server is initially ahead - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -495,7 +486,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
 	test_grep "fatal: remote error: upload-pack: not our ref" err
 '
 
-test_expect_success 'server is initially ahead - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially ahead - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -507,7 +498,7 @@ test_expect_success 'server is initially ahead - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - no ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - no ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant false &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -519,7 +510,7 @@ test_expect_success 'server is initially behind - no ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server is initially behind - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server is initially behind - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
@@ -531,7 +522,7 @@ test_expect_success 'server is initially behind - ref in want' '
 	test_cmp expected actual
 '
 
-test_expect_success 'server loses a ref - ref in want' '
+test_expect_success PERL_TEST_HELPERS 'server loses a ref - ref in want' '
 	git -C "$REPO" config uploadpack.allowRefInWant true &&
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&

-- 
2.49.0.604.gff1f9ca942.dirty


^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite
  2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
                     ` (19 preceding siblings ...)
  2025-04-03  5:06   ` [PATCH v4 20/20] t5703: refactor test " Patrick Steinhardt
@ 2025-04-03 12:12   ` Johannes Schindelin
  2025-04-08  0:32     ` Junio C Hamano
  20 siblings, 1 reply; 121+ messages in thread
From: Johannes Schindelin @ 2025-04-03 12:12 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, Eric Sunshine, Karthik Nayak, Phillip Wood

Hi Patrick,

On Thu, 3 Apr 2025, Patrick Steinhardt wrote:

> Changes in v4:
>   - Improve a couple of commit messages to better explain the changes.
>   - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im

Looks good to me, as well as the range-diff.

Thank you,
Johannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite
  2025-04-03 12:12   ` [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite Johannes Schindelin
@ 2025-04-08  0:32     ` Junio C Hamano
  0 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2025-04-08  0:32 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Patrick Steinhardt, git, Eric Sunshine, Karthik Nayak,
	Phillip Wood

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> Hi Patrick,
>
> On Thu, 3 Apr 2025, Patrick Steinhardt wrote:
>
>> Changes in v4:
>>   - Improve a couple of commit messages to better explain the changes.
>>   - Link to v3: https://lore.kernel.org/r/20250327-b4-pks-t-perlless-v3-0-b436de9da1b8@pks.im
>
> Looks good to me, as well as the range-diff.

Thanks, both of you.  Will replace and queue.
Let me mark the topic for 'next'.

^ permalink raw reply	[flat|nested] 121+ messages in thread

end of thread, other threads:[~2025-04-08  0:32 UTC | newest]

Thread overview: 121+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-20  9:35 [PATCH 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
2025-03-20 18:36   ` Eric Sunshine
2025-03-20  9:35 ` [PATCH 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
2025-03-21  9:52   ` Karthik Nayak
2025-03-20  9:35 ` [PATCH 03/20] t: adapt character translation helpers " Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
2025-03-21  9:56   ` Karthik Nayak
2025-03-20  9:35 ` [PATCH 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
2025-03-20 18:55   ` Eric Sunshine
2025-03-24 12:46     ` Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
2025-03-24 16:16   ` Phillip Wood
2025-03-20  9:35 ` [PATCH 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
2025-03-20 19:33   ` Eric Sunshine
2025-03-24 12:46     ` Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
2025-03-20 19:37   ` Eric Sunshine
2025-03-24 12:46     ` Patrick Steinhardt
2025-03-24 16:07       ` Eric Sunshine
2025-03-25 12:42         ` Patrick Steinhardt
2025-03-24 16:16   ` Phillip Wood
2025-03-25 12:43     ` Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
2025-03-20 19:41   ` Eric Sunshine
2025-03-24 12:46     ` Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
2025-03-20  9:35 ` [PATCH 20/20] t5703: refactor test " Patrick Steinhardt
2025-03-25 13:14 ` [PATCH v2 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 03/20] t: adapt character translation helpers " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
2025-03-25 14:35     ` Phillip Wood
2025-03-27 10:19       ` Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
2025-03-25 13:14   ` [PATCH v2 20/20] t5703: refactor test " Patrick Steinhardt
2025-03-27 10:36 ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Patrick Steinhardt
2025-03-27 10:36   ` [PATCH v3 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 03/20] t: adapt character translation helpers " Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
2025-04-01 18:26     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-04-02 19:10         ` Johannes Schindelin
2025-04-03  5:05           ` Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
2025-04-01 18:32     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
2025-04-01 18:35     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
2025-04-01 18:55     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-04-02 19:17         ` Johannes Schindelin
2025-03-27 10:37   ` [PATCH v3 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
2025-04-01 18:56     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
2025-04-01 19:04     ` Johannes Schindelin
2025-04-02  7:16       ` Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
2025-03-27 10:37   ` [PATCH v3 20/20] t5703: refactor test " Patrick Steinhardt
2025-03-28 10:29   ` [PATCH v3 00/20] t: drop Perl as a mandatory prerequisite Phillip Wood
2025-04-02 19:32   ` Johannes Schindelin
2025-04-03  5:05 ` [PATCH v4 " Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 01/20] t: skip chain lint when PERL_PATH is unset Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 02/20] t: refactor environment sanitization to not use Perl Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 03/20] t: adapt character translation helpers " Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 04/20] t: adapt `test_copy_bytes()` " Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 05/20] t: adapt `test_readlink()` " Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 06/20] t: introduce PERL_TEST_HELPERS prerequisite Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 07/20] t: adapt existing PERL prerequisites Patrick Steinhardt
2025-04-03  5:05   ` [PATCH v4 08/20] meson: stop requiring Perl when tests are enabled Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 09/20] Makefile: stop requiring Perl when running tests Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 10/20] t: refactor tests depending on Perl transliteration operator Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 11/20] t: refactor tests depending on Perl substitution operator Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 12/20] t: refactor tests depending on Perl to print data Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 13/20] t: refactor tests depending on Perl for textconv scripts Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 14/20] t/lib-gpg: refactor `sanitize_pgp()` to not depend on Perl Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 15/20] t/lib-t6000: refactor `name_from_description()` " Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 16/20] t/lib-httpd: refactor "one-time-perl" CGI script " Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 17/20] t0021: refactor `generate_random_characters()` " Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 18/20] t0210: refactor trace2 scrubbing to not use Perl Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 19/20] t5316: refactor `max_chain()` to not depend on Perl Patrick Steinhardt
2025-04-03  5:06   ` [PATCH v4 20/20] t5703: refactor test " Patrick Steinhardt
2025-04-03 12:12   ` [PATCH v4 00/20] t: drop Perl as a mandatory prerequisite Johannes Schindelin
2025-04-08  0:32     ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).