From 3f5ea701cf8b9abf4fb97804daaee15889b15987 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Wed, 4 Mar 2026 09:04:15 +0100
Subject: [PATCH v3 8/8] pgindent: Add easy way of getting perltidy

We need a very specific perltidy version, but getting that installed is
quite a hassle. Especially for people who don't use perl on a daily
basis. This adds a small script to download the exact perltidy version
that we need.
---
 src/tools/pgindent/.gitignore   |  1 +
 src/tools/pgindent/README       | 16 ++++-----
 src/tools/pgindent/get_perltidy | 62 +++++++++++++++++++++++++++++++++
 src/tools/pgindent/pgindent     | 30 +++++++++++++---
 4 files changed, 96 insertions(+), 13 deletions(-)
 create mode 100644 src/tools/pgindent/.gitignore
 create mode 100755 src/tools/pgindent/get_perltidy

diff --git a/src/tools/pgindent/.gitignore b/src/tools/pgindent/.gitignore
new file mode 100644
index 00000000000..1497217113b
--- /dev/null
+++ b/src/tools/pgindent/.gitignore
@@ -0,0 +1 @@
+/perltidy/
diff --git a/src/tools/pgindent/README b/src/tools/pgindent/README
index 2e31471d7e6..264038e7e09 100644
--- a/src/tools/pgindent/README
+++ b/src/tools/pgindent/README
@@ -17,14 +17,14 @@ PREREQUISITES:
 
 2) Install perltidy.  Please be sure it is version 20230309 (older and newer
    versions make different formatting choices, and we want consistency).
-   You can get the correct version from
-   https://cpan.metacpan.org/authors/id/S/SH/SHANCOCK/
-   To install, follow the usual install process for a Perl module
-   ("man perlmodinstall" explains it).  Or, if you have cpan installed,
-   this should work:
-   cpan SHANCOCK/Perl-Tidy-20230309.tar.gz
-   Or if you have cpanm installed, you can just use:
-   cpanm https://cpan.metacpan.org/authors/id/S/SH/SHANCOCK/Perl-Tidy-20230309.tar.gz
+
+   The easiest way is to use the get_perltidy script, which downloads,
+   verifies, and installs the correct version into the source tree:
+
+	src/tools/pgindent/get_perltidy
+
+   This installs perltidy into src/tools/pgindent/perltidy/, which
+   pgindent will find automatically.
 
 
 DOING THE INDENT RUN BEFORE A NORMAL COMMIT:
diff --git a/src/tools/pgindent/get_perltidy b/src/tools/pgindent/get_perltidy
new file mode 100755
index 00000000000..09ce4a195cb
--- /dev/null
+++ b/src/tools/pgindent/get_perltidy
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# src/tools/pgindent/get_perltidy
+#
+# Downloads and installs perltidy 20230309 into src/tools/pgindent/perltidy/.
+
+set -e
+
+PERLTIDY_VERSION=20230309
+PERLTIDY_TARBALL="Perl-Tidy-${PERLTIDY_VERSION}.tar.gz"
+PERLTIDY_URL="https://cpan.metacpan.org/authors/id/S/SH/SHANCOCK/${PERLTIDY_TARBALL}"
+PERLTIDY_SHA256="e22949a208c618d671a18c5829b451abbe9da0da2cddd78fdbfcb036c7361c18"
+
+# Determine the directory this script lives in, i.e. src/tools/pgindent
+SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
+
+PERLTIDY_DIR="$SCRIPT_DIR/perltidy"
+PERLTIDY_BIN="$PERLTIDY_DIR/bin/perltidy"
+
+# Check if already installed with the correct version
+if [ -x "$PERLTIDY_BIN" ]; then
+	perltidy_lib="$PERLTIDY_DIR/lib/perl5"
+	installed_version=$(PERL5LIB="$perltidy_lib${PERL5LIB:+:$PERL5LIB}" "$PERLTIDY_BIN" -v 2>/dev/null || true)
+	if echo "$installed_version" | grep -q "$PERLTIDY_VERSION"; then
+		echo "perltidy $PERLTIDY_VERSION is already installed in $PERLTIDY_DIR"
+		exit 0
+	fi
+fi
+
+WORK_DIR=$(mktemp -d)
+trap 'rm -rf "$WORK_DIR"' EXIT
+
+# Download
+TARBALL="$WORK_DIR/$PERLTIDY_TARBALL"
+if command -v curl >/dev/null 2>&1; then
+	curl -sSL -o "$TARBALL" "$PERLTIDY_URL"
+elif command -v wget >/dev/null 2>&1; then
+	wget -q -O "$TARBALL" "$PERLTIDY_URL"
+else
+	echo "error: neither curl nor wget found" >&2
+	exit 1
+fi
+
+# Verify SHA256
+if command -v sha256sum >/dev/null 2>&1; then
+	echo "$PERLTIDY_SHA256  $TARBALL" | sha256sum -c - >/dev/null
+elif command -v shasum >/dev/null 2>&1; then
+	echo "$PERLTIDY_SHA256  $TARBALL" | shasum -a 256 -c - >/dev/null
+else
+	echo "error: neither sha256sum nor shasum found" >&2
+	exit 1
+fi
+
+# Extract, build, install
+cd "$WORK_DIR"
+tar xzf "$TARBALL"
+cd "Perl-Tidy-${PERLTIDY_VERSION}"
+perl Makefile.PL INSTALL_BASE="$PERLTIDY_DIR" >/dev/null
+make >/dev/null
+make install >/dev/null
+
+echo "perltidy $PERLTIDY_VERSION installed in $PERLTIDY_DIR"
diff --git a/src/tools/pgindent/pgindent b/src/tools/pgindent/pgindent
index 9d635b7a22b..8003dadc4e1 100755
--- a/src/tools/pgindent/pgindent
+++ b/src/tools/pgindent/pgindent
@@ -112,14 +112,34 @@ usage("Cannot use --commit with command line file list")
 # dir, then default location
 $typedefs_file ||= $ENV{PGTYPEDEFS};
 
-# get perltidy location: command line wins, then environment, then default.
-# --perltidy (with or without a path) and --perl-only all imply perltidy is
-# wanted, falling back to the PERLTIDY env var, then "perltidy" in PATH.
-my $perltidy = $perltidy_arg || $ENV{PERLTIDY}
-  || (defined($perltidy_arg) || $perl_only ? "perltidy" : undef);
+# get perltidy location: command line wins, then environment, then try to
+# find a get_perltidy-installed copy in the source tree, then fall back to
+# PATH.  --perltidy (with or without a path) and --perl-only all imply
+# perltidy is wanted.
+my $perltidy = $perltidy_arg || $ENV{PERLTIDY};
 
 my $sourcedir = locate_sourcedir();
 
+if (!$perltidy && (defined($perltidy_arg) || $perl_only) && $sourcedir)
+{
+	# Look for a get_perltidy-installed perltidy in the source tree.
+	my $candidate = "$sourcedir/perltidy/bin/perltidy";
+	if (-x $candidate)
+	{
+		$perltidy = $candidate;
+
+		# Local installs need PERL5LIB set so perltidy can find its
+		# modules.
+		my $libdir = "$sourcedir/perltidy/lib/perl5";
+		if (-d $libdir)
+		{
+			$ENV{PERL5LIB} =
+			  $ENV{PERL5LIB} ? "$libdir:$ENV{PERL5LIB}" : $libdir;
+		}
+	}
+}
+$perltidy ||= (defined($perltidy_arg) || $perl_only ? "perltidy" : undef);
+
 # get indent location: command line wins, then environment, then try to find
 # a compiled pg_bsd_indent in the source tree, then fall back to PATH.
 $indent ||= $ENV{PGINDENT} || $ENV{INDENT};
-- 
2.53.0

