App-ChangeShebang
view release on metacpan or search on metacpan
lib/App/ChangeShebang.pm view on Meta::CPAN
package App::ChangeShebang v1.0.0;
use v5.24;
use warnings;
use experimental qw(lexical_subs signatures);
use ExtUtils::MakeMaker ();
use File::Basename ();
use File::Temp ();
use Getopt::Long ();
use Pod::Usage ();
our $TRIAL = 0;
sub new ($class) {
bless {}, $class;
}
sub parse_options ($self, @argv) {
my $parser = Getopt::Long::Parser->new(
config => [qw(no_auto_abbrev no_ignore_case)],
);
$parser->getoptionsfromarray(
\@argv,
"version|v" => sub (@) { printf "%s %s\n", __PACKAGE__, __PACKAGE__->VERSION; exit },
"quiet|q" => \$self->{quiet},
"force|f" => \$self->{force},
"help|h" => sub (@) { Pod::Usage::pod2usage(0) },
) or Pod::Usage::pod2usage(1);
my @file = @argv;
if (!@file) {
warn "Missing file arguments.\n";
Pod::Usage::pod2usage(1);
}
$self->{file} = \@file;
$self;
}
sub run ($self) {
for my $file ($self->{file}->@*) {
next unless -f $file && !-l $file;
next unless $self->is_perl_shebang( $file );
unless ($self->{force}) {
my $anser = ExtUtils::MakeMaker::prompt( "change shebang line of $file? (y/N)", "N" );
next if $anser !~ /^y(es)?$/i;
}
$self->change_shebang($file);
warn "changed shebang line of $file\n" unless $self->{quiet};
}
}
sub is_perl_shebang ($self, $file) {
open my $fh, "<:raw", $file or die "open $file: $!\n";
read $fh, my $first, 100 or die "read $file: $!\n";
return $first =~ /^#!([^\n]*)perl/ ? 1 : 0;
}
my $remove = do {
my $s = qr/[ \t]*/;
my $w = qr/[^\n]*/;
my $running_under_some_shell = qr/\n*
$s eval $s ['"] exec $w \n
$s if $s (?:0|\$running_under_some_shell) $w \n
/xsm;
my $shebang = qr/\n*
\#! $w \n
/xsm;
qr/\A(?:$running_under_some_shell|$shebang)+/;
};
sub change_shebang ($self, $file) {
my $content = do {
open my $fh, "<:raw", $file or die "open $file: $!\n";
local $/; <$fh>;
};
$content =~ s/$remove//;
my $mode = (stat $file)[2];
my ($tmp_fh, $tmp_name) = File::Temp::tempfile UNLINK => 0, DIR => File::Basename::dirname($file);
chmod $mode, $tmp_name;
print {$tmp_fh} <<'...';
#!/bin/sh
exec "$(dirname "$0")"/perl -x "$0" "$@"
#!perl
...
print {$tmp_fh} $content;
close $tmp_fh;
rename $tmp_name, $file or die "rename $tmp_name, $file: $!\n";
}
1;
__END__
=encoding utf-8
=head1 NAME
App::ChangeShebang - change shebang lines for relocatable perl
=head1 SYNOPSIS
> change-shebang /path/to/bin/script.pl
( run in 1.204 second using v1.01-cache-2.11-cpan-6aa56a78535 )