File Coverage

blib/lib/App/Highlander.pm
Criterion Covered Total %
statement 45 45 100.0
branch 10 14 71.4
condition 7 13 53.8
subroutine 11 11 100.0
pod 2 2 100.0
total 75 85 88.2


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.002';
4 6     6   3415 use strict;
  6         11  
  6         138  
5 6     6   31 use warnings;
  6         9  
  6         159  
6              
7 6     6   4480 use English qw(-no_match_vars);
  6         23156  
  6         31  
8 6     6   2589 use Fcntl qw(:flock);
  6         12  
  6         580  
9 6     6   6797 use Path::Tiny;
  6         74524  
  6         3321  
10              
11             our $LOCKDIR;
12             sub import {
13 6     6   121 my ($self, %args) = @_;
14              
15             _create_if_not_exists(
16 6   50     69 $LOCKDIR = $args{LOCKDIR} // '/var/highlander/'
17             );
18              
19 6         134 return;
20             }
21              
22             our $LOCKFILE;
23             sub get_lock {
24 8     8 1 494 my ($lock_string) = @_;
25 8         76 $lock_string = _build_lock_string($lock_string);
26            
27 8 50       2527 open $LOCKFILE, '>>', $lock_string
28             or die "Unable to create LOCKFILE '$lock_string': $!";
29              
30 8         21 my $got_lock;
31 8 100       89 if ( $got_lock = flock($LOCKFILE, LOCK_EX|LOCK_NB) ) {
32 6         12 print {$LOCKFILE} $PID;
  6         111  
33             }
34            
35 8 100       225 return $got_lock ? $lock_string : 0;
36             }
37              
38             sub release_lock {
39 4     4 1 29 my ($lock_string) = @_;
40 4 50       39 return unless _have_lock($lock_string);
41              
42 4         62 $lock_string = _build_lock_string($lock_string);
43 4 50 33     1238 return close($LOCKFILE) && unlink($lock_string)
44             ? $lock_string
45             : 0;
46             }
47              
48             sub _have_lock {
49 4     4   24 my ($lock_string) = @_;
50 4         35 $lock_string = _build_lock_string($lock_string);
51              
52 4         479 my $PID_PATTERN = qr/^$PID/;
53 4   33     18042 return -e $lock_string && `cat $lock_string` =~ m/$PID_PATTERN/;
54             }
55              
56             sub _build_lock_string {
57 16     16   74 my ($lock_string) = @_;
58 16   100     175 $lock_string //= '';
59            
60 16         298 my ($normalized_programname) = $PROGRAM_NAME;
61 16         453 $normalized_programname =~ s|^.*/||;
62 16         198 $normalized_programname =~ s|\..*$||;
63            
64 16   66     277 my $lock_name = join ':',
65             ($lock_string || ()),"${normalized_programname}.lock";
66 16         310 return path($LOCKDIR, $lock_name)->canonpath;
67             }
68              
69             sub _create_if_not_exists {
70 6     6   12 my ($dir) = @_;
71 6 100       203 return if -e $dir;
72              
73 1 50       193 mkdir $dir, 0755
74             or die "Unable to make directory '$dir': $OS_ERROR";
75              
76 1         3 return;
77             }
78              
79             1;
80              
81             __END__