The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

#!/usr/bin/env perl
use strict;
use warnings FATAL => 'uninitialized';
use experimental 'signatures';
use Cwd 'abs_path';
my ($mydir, $myname);
BEGIN {
my $location = (-l $0) ? abs_path($0) : $0;
$location =~ /(.*?)([^\/]+)\z/s or die "?";
($mydir, $myname) = ($1, $2);
}
use lib "$mydir/../lib";
use Chj::IsPerl 'is_perl_file';
sub usage {
print STDERR map {"$_\n"} @_ if @_;
print "$myname
This is meant to be symlinked to \`.git/hooks\`. It gets all paths
from git status which are perl files and runs \`perltidy\` on them.
";
exit(@_ ? 1 : 0);
}
sub xopen_sender {
my (@cmd) = @_;
open my $in, "-|", @cmd or die "can't open input pipe to @cmd: $!";
$in
}
my $top = `git rev-parse --show-toplevel`;
$? == 0 or die "error from cmd";
chomp $top;
chdir $top or die "can't chdir to Git working dir top '$top': $!";
sub git_status () {
local $/ = "\0";
my $in = xopen_sender qw(git status -z);
my @items;
while (defined(my $item = <$in>)) {
chomp $item;
# X = staged, Y = unstaged changes
my ($X, $Y, $path) = $item =~ /(.)(.) (.*)/s
or die "invalid git-status -z item '$item'";
push @items, [$X, $Y, $path]
}
close $in or die "git status -z: $!";
$? == 0 or die "git status -z failed";
\@items
}
sub filter_status ($items) {
my %indicating_modification = map { $_ => 1 } qw(A M R C);
my @paths;
for my $item (@$items) {
# X = staged, Y = unstaged changes
my ($X, $Y, $path) = @$item;
my $x = $indicating_modification{$X};
my $y = $indicating_modification{$Y};
next unless ($x or $y);
if (is_perl_file($path)) {
if ($x and $y) {
warn "$path: can't perltidy only part, thus skipped\n";
} else {
push @paths, $path;
}
}
}
\@paths
}
my $paths = filter_status git_status;
#use FP::Repl;repl;exit;
if (@$paths) {
my @cmd = ("perltidy", @$paths);
warn "running @cmd...\n";
system @cmd;
$? == 0 or die "perltidy failed";
system "git", "add", "--", @$paths;
$? == 0 or die "git add failed";
my $items = git_status;
if (!@$items) {
warn "Nothing to commit after perltidy, aborting commit.\n";
exit 1
}
}