File Coverage

blib/lib/App/ChangeShebang.pm
Criterion Covered Total %
statement 56 64 87.5
branch 13 24 54.1
condition 1 3 33.3
subroutine 12 15 80.0
pod 0 6 0.0
total 82 112 73.2


line stmt bran cond sub pod time code
1             package App::ChangeShebang 0.10;
2 2     2   166340 use v5.16;
  2         19  
3 2     2   9 use warnings;
  2         4  
  2         59  
4              
5 2     2   1668 use Getopt::Long ();
  2         24429  
  2         60  
6 2     2   1137 use Pod::Usage ();
  2         103052  
  2         52  
7 2     2   1916 use ExtUtils::MakeMaker ();
  2         200262  
  2         59  
8 2     2   14 use File::Basename ();
  2         5  
  2         28  
9 2     2   760 use File::Temp ();
  2         19216  
  2         1709  
10              
11 0     0 0 0 sub prompt { ExtUtils::MakeMaker::prompt(@_) }
12              
13             sub new {
14 4     4 0 18756 my $class = shift;
15 4         49 bless {@_}, $class;
16             }
17              
18             sub parse_options {
19 4     4 0 16 my ($self, @argv) = @_;
20 4         31 my $parser = Getopt::Long::Parser->new(
21             config => [qw(no_auto_abbrev no_ignore_case)],
22             );
23             $parser->getoptionsfromarray(
24             \@argv,
25 0     0   0 "version|v" => sub { printf "%s %s\n", __PACKAGE__, __PACKAGE__->VERSION; exit },
  0         0  
26             "quiet|q" => \$self->{quiet},
27             "force|f" => \$self->{force},
28 0     0   0 "help|h" => sub { Pod::Usage::pod2usage(0) },
29 4 50       400 ) or Pod::Usage::pod2usage(1);
30              
31 4         2301 my @file = @argv;
32 4 50       10 if (!@file) {
33 0         0 warn "Missing file arguments.\n";
34 0         0 Pod::Usage::pod2usage(1);
35             }
36 4         11 $self->{file} = \@file;
37 4         30 $self;
38             }
39              
40             sub run {
41 4     4 0 11 my $self = shift;
42 4         6 for my $file (@{ $self->{file} }) {
  4         12  
43 12 50 33     288 next unless -f $file && !-l $file;
44 12 100       52 next unless $self->is_perl_shebang( $file );
45 11 50       36 unless ($self->{force}) {
46 0         0 my $anser = prompt "change shebang line of $file? (y/N)", "N";
47 0 0       0 next if $anser !~ /^y(es)?$/i;
48             }
49 11         37 $self->change_shebang($file);
50 11 50       54 warn "changed shebang line of $file\n" unless $self->{quiet};
51             }
52             }
53              
54             sub is_perl_shebang {
55 12     12 0 26 my ($self, $file) = @_;
56 12 50       417 open my $fh, "<:raw", $file or die "open $file: $!\n";
57 12 50       217 read $fh, my $first, 100 or die "read $file: $!\n";
58 12 100       273 return $first =~ /^#!([^\n]*)perl/ ? 1 : 0;
59             }
60              
61             my $remove = do {
62             my $s = qr/[ \t]*/;
63             my $w = qr/[^\n]*/;
64             my $running_under_some_shell = qr/\n*
65             $s eval $s ['"] exec $w \n
66             $s if $s (?:0|\$running_under_some_shell) $w \n
67             /xsm;
68             my $shebang = qr/\n*
69             \#! $w \n
70             /xsm;
71             qr/\A(?:$running_under_some_shell|$shebang)+/;
72             };
73              
74             sub change_shebang {
75 11     11 0 33 my ($self, $file) = @_;
76 11         17 my $content = do {
77 11 50       341 open my $fh, "<:raw", $file or die "open $file: $!\n";
78 11         55 local $/; <$fh>;
  11         340  
79             };
80              
81 11         139 $content =~ s/$remove//;
82              
83 11         138 my $mode = (stat $file)[2];
84              
85 11         394 my ($tmp_fh, $tmp_name) = File::Temp::tempfile UNLINK => 0, DIR => File::Basename::dirname($file);
86 11         3538 chmod $mode, $tmp_name;
87 11         29 print {$tmp_fh} <<'...';
  11         55  
88             #!/bin/sh
89             exec "$(dirname "$0")"/perl -x "$0" "$@"
90             #!perl
91             ...
92 11         22 print {$tmp_fh} $content;
  11         19  
93 11         344 close $tmp_fh;
94 11 50       1097 rename $tmp_name, $file or die "rename $tmp_name, $file: $!\n";
95             }
96              
97              
98             1;
99             __END__