diff --git a/src/tools/pgindent/pgperltidy b/src/tools/pgindent/pgperltidy
index 5e704119eb..388c113526 100755
--- a/src/tools/pgindent/pgperltidy
+++ b/src/tools/pgindent/pgperltidy
@@ -1,12 +1,162 @@
-#!/bin/sh
+#!/usr/bin/perl
 
 # src/tools/pgindent/pgperltidy
 
-set -e
+use strict;
+use warnings;
 
-# set this to override default perltidy program:
-PERLTIDY=${PERLTIDY:-perltidy}
+use Getopt::Long;
+use FindBin;
+use File::Find;
+use Perl::Tidy;
 
-. src/tools/perlcheck/find_perl_files
+# we require this exact version. See README.
+die "wrong perltidy version $Perl::Tidy::VERSION"
+  unless $Perl::Tidy::VERSION eq '20170521';
+
+# make sure we're in the source root if we need to look for files
+chdir "$FindBin::RealBin/../../.." unless @ARGV;
+
+my ($show_diff, $silent_diff, $help);
+
+$help = 0;
+
+my %options = (
+	"help"               => \$help,
+	"show-diff"          => \$show_diff,
+	"silent-diff"        => \$silent_diff,);
+GetOptions(%options) || usage("bad command line argument");
+
+usage() if $help;
+
+my @files;
+
+# get the filtered list of files
+if (@ARGV)
+{
+	filter_perl_files();
+}
+else
+{
+	File::Find::find(\&wanted, ".");
+}
+
+# process according to the command switches
+if ($silent_diff || $show_diff)
+{
+	indent_files_diff();
+}
+else
+{
+	indent_files_in_place();
+}
+
+exit 0;
+
+# non-destructive perltidy mode
+sub indent_files_diff
+{
+	my $diff_found = 0;
+	foreach my $file (@files)
+	{
+		my $error_flag = Perl::Tidy::perltidy(
+			source            => $file,
+            destination       => "$file.tdy",
+            perltidyrc        => "$FindBin::RealBin/perltidyrc",
+		   );
+		if ($error_flag)
+		{
+			unlink "$file.tdy";
+			die "pgperltidy error!";
+		}
+		my $diff = `diff -ud -F '^sub ' $file $file.tdy 2>&1`;
+		unlink "$file.tdy";
+		next unless $diff;
+		exit 2 if ($silent_diff);
+		$diff_found = 1;
+		print $diff;
+	}
+}
+
+# destructive perltidy in place
+# expects that the perltidyrc will have --backup-and-modify-in-place
+sub indent_files_in_place
+{
+	foreach my $file (@files)
+	{
+		my $error_flag = Perl::Tidy::perltidy(
+			source            => $file,
+            perltidyrc        => "$FindBin::RealBin/perltidyrc",
+		   );
+		if ($error_flag)
+		{
+			die "pgperltidy error!";
+		}
+	}
+}
+
+# subroutine for use with File::Find::find
+sub wanted
+{
+    my $mode;
+
+    ($mode = (lstat($_))[2]) &&
+	  -f _ &&
+	  (/^.*\.p[lm]\z/s ||
+	   (!/^.*\.dat\z/s && (($mode & 0100) == 0100) &&
+		`file $_ 2>/dev/null` =~/:.*perl[0-9]*$/i)) &&
+	   push(@files, $File::Find::name);
+}
+
+# Similar but filtering files specified in @ARGV
+sub filter_perl_files
+{
+	while (my $file = shift @ARGV)
+	{
+		if (! -f $file)
+		{
+			die "can't find $file";
+		}
+		# ignore .dat files in case they are found
+		next if $file =~ /\.dat$/;
+		if ($file =~ /\.p[lm]\z/)
+		{
+			# file has an explicit perl extension, nothing more to test
+			push @files, $file;
+			next;
+		}
+		my $mode = (lstat(_))[2];
+		# check if it's executable by owner
+		next unless (($mode & 0100) == 0100);
+		# check if `file` says it's a perl file
+		if (`file $file 2>/dev/null` =~/:.*perl[0-9]*$/i)
+		{
+			push @files, $file;
+		}
+	}
+}
+
+
+sub usage
+{
+	my $message  = shift;
+	my $helptext = <<'EOF';
+Usage:
+pgperltidy [OPTION]... [FILE]...
+Options:
+	--help                  show this message and quit
+	--show-diff             show the changes that would be made
+	--silent-diff           exit with status 2 if any changes would be made
+EOF
+	if ($help)
+	{
+		print $helptext;
+		exit 0;
+	}
+	else
+	{
+		print STDERR "$message\n", $helptext;
+		exit 1;
+	}
+}
 
-find_perl_files | xargs $PERLTIDY --profile=src/tools/pgindent/perltidyrc
