File Coverage

blib/lib/App/Highlander.pm
Criterion Covered Total %
statement 47 49 95.9
branch 8 14 57.1
condition 7 14 50.0
subroutine 12 12 100.0
pod 2 2 100.0
total 76 91 83.5


line stmt bran cond sub pod time code
1             # ABSTRACT: Module that provides simple named locks
2             package App::Highlander;
3             $App::Highlander::VERSION = '0.003';
4 6     6   3610 use strict;
  6         12  
  6         145  
5 6     6   30 use warnings;
  6         9  
  6         158  
6              
7 6     6   4540 use English qw(-no_match_vars);
  6         23333  
  6         32  
8 6     6   2618 use Fcntl qw(:flock);
  6         12  
  6         626  
9 6     6   6997 use File::Temp qw/tempdir/;
  6         133634  
  6         403  
10 6     6   7069 use Path::Tiny;
  6         66347  
  6         3534  
11              
12             our $LOCKDIR;
13             sub import {
14 6     6   105 my ($self, %args) = @_;
15              
16             _create_if_not_exists(
17 6   33     50 $LOCKDIR = $args{LOCKDIR} // tempdir( CLEANUP => 1 )
18             );
19 6         79 print "LOCKDIR='$LOCKDIR'\n";
20 6         199 return;
21             }
22              
23             our $LOCKFILE;
24             sub get_lock {
25 8     8 1 353 my ($lock_string) = @_;
26 8         80 $lock_string = _build_lock_string($lock_string);
27            
28 8 50       1789 open $LOCKFILE, '>>', $lock_string
29             or die "Unable to create LOCKFILE '$lock_string': $!";
30              
31 8         17 my $got_lock;
32 8 100       70 if ( $got_lock = flock($LOCKFILE, LOCK_EX|LOCK_NB) ) {
33 6         12 print {$LOCKFILE} $PID;
  6         100  
34             }
35            
36 8 100       154 return $got_lock ? $lock_string : 0;
37             }
38              
39             sub release_lock {
40 4     4 1 45 my ($lock_string) = @_;
41 4 50       47 return unless _have_lock($lock_string);
42              
43 4         86 $lock_string = _build_lock_string($lock_string);
44 4 50 33     1437 return close($LOCKFILE) && unlink($lock_string)
45             ? $lock_string
46             : 0;
47             }
48              
49             sub _have_lock {
50 4     4   31 my ($lock_string) = @_;
51 4         48 $lock_string = _build_lock_string($lock_string);
52              
53 4         567 my $PID_PATTERN = qr/^$PID/;
54 4   33     18655 return -e $lock_string && `cat $lock_string` =~ m/$PID_PATTERN/;
55             }
56              
57             sub _build_lock_string {
58 16     16   110 my ($lock_string) = @_;
59 16   100     150 $lock_string //= '';
60            
61 16         234 my ($normalized_programname) = $PROGRAM_NAME;
62 16         347 $normalized_programname =~ s|^.*/||;
63 16         177 $normalized_programname =~ s|\..*$||;
64            
65 16   66     247 my $lock_name = join ':',
66             ($lock_string || ()),"${normalized_programname}.lock";
67 16         252 return path($LOCKDIR, $lock_name)->canonpath;
68             }
69              
70             sub _create_if_not_exists {
71 6     6   3869 my ($dir) = @_;
72 6 50       97 return if -e $dir;
73              
74 0 0         mkdir $dir, 0755
75             or die "Unable to make directory '$dir': $OS_ERROR";
76              
77 0           return;
78             }
79              
80             1;
81              
82             __END__