File Coverage

blib/lib/Tie/DiskUsage.pm
Criterion Covered Total %
statement 66 70 94.2
branch 10 16 62.5
condition 10 15 66.6
subroutine 14 16 87.5
pod n/a
total 100 117 85.4


line stmt bran cond sub pod time code
1             package Tie::DiskUsage;
2              
3 3     3   80319 use strict;
  3         6  
  3         93  
4 3     3   12 use warnings;
  3         6  
  3         90  
5              
6 3     3   12 use Carp qw(croak);
  3         9  
  3         158  
7 3     3   1159 use Symbol ();
  3         1919  
  3         2862  
8              
9             our ($VERSION, $DU_BIN);
10              
11             $VERSION = '0.21_05';
12              
13             $DU_BIN = '/usr/bin/du';
14              
15             sub TIEHASH
16             {
17 3     3   61 my $class = shift;
18              
19 3         6 my $du = _locate_du();
20 3         6 my $path = shift @_;
21 3         5 my @opts = @_;
22              
23 3         8 _validate($path, \@opts);
24              
25 3         19 return bless { du => $du, path => $path, opts => \@opts }, $class;
26             }
27              
28             sub EXISTS
29             {
30 1     1   9 my $self = shift;
31 1         2 my ($key) = @_;
32              
33 1         4 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, $key);
34              
35 1         26 return exists $usage->{$key};
36             }
37              
38             sub FETCH
39             {
40 3     3   60 my $self = shift;
41 3         5 my ($key) = @_;
42              
43 3         12 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, $key);
44              
45 3         54 return $usage->{$key};
46             }
47              
48             sub FIRSTKEY
49             {
50 3     3   6 my $self = shift;
51              
52 3         12 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, undef);
53              
54 3         24 my @keys = sort keys %$usage;
55 3         7 my $key = shift @keys;
56 3         10 delete $self->{'keys'};
57 3         12 $self->{'keys'} = [ @keys ];
58              
59 3         44 return $key;
60             }
61              
62             sub NEXTKEY
63             {
64 2     2   4 my $self = shift;
65              
66 2         3 return shift @{$self->{'keys'}};
  2         34  
67             }
68              
69             sub SCALAR
70             {
71 1     1   3 my $self = shift;
72              
73 1         7 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, undef);
74              
75 1         20 return scalar %$usage;
76             }
77              
78       3     sub UNTIE {}
79              
80 0     0   0 *CLEAR = *DELETE = *STORE = sub { croak 'Tied hash is read-only' };
81              
82             sub _validate
83             {
84 10     10   2035 my ($path, $opts) = @_;
85              
86 10 100 100     18 @$opts = map { (defined && length) ? $_ : () } @$opts;
  6         36  
87              
88 10         25 my %errors = (
89             not_exists => 'an existing path',
90             not_option => 'options to be short or long',
91             );
92 10     0   29 my $error = sub { "tie() requires $_[0]" };
  0         0  
93              
94 10         30 my $valid_opt = qr{
95             ^(?:
96             -\w (?:(?: \ +?)\S+)? # short
97             | --\w{2}[-\w]*? (?:(?:\=|\ +?)\S+)? # long
98             )$
99             }ix;
100              
101             croak $error->($errors{not_exists})
102 10 50 66     148 if defined $path && !-e $path;
103              
104             croak $error->($errors{not_option})
105 10 50 66     109 if @$opts && grep !/$valid_opt/, @$opts;
106             }
107              
108             sub _locate_du
109             {
110 3 100   3   91 if (!-e $DU_BIN) {
111 1         2 my $du_which = do { require File::Which; File::Which::which('du') };
  1         520  
  1         816  
112 1 50       125 croak "Cannot locate du: $!" unless defined $du_which;
113              
114 1         3 return $du_which;
115             }
116             else {
117 2 50       22 croak "Cannot run `$DU_BIN': Not executable" unless -x $DU_BIN;
118              
119 2         4 return $DU_BIN;
120             }
121             }
122              
123             sub _parse_usage
124             {
125 8     8   12 my ($du, $path, $opts, $key) = @_;
126 8   33     17 $path ||= do { require Cwd; Cwd::getcwd() };
  0         0  
  0         0  
127              
128 8         13 my $pipe = Symbol::gensym();
129 8 50       8808 open($pipe, "$du @$opts $path |") or exit(1);
130              
131 8         40 my %usage;
132 8         7565 while (my $line = <$pipe>) {
133 8         182 my ($size, $item) = $line =~ /^(.+?) \s+? (.+)$/x;
134             # optimisation for EXISTS/FETCH
135 8 50 66     69 next if defined $key && $key ne $item;
136 8         262 $usage{$item} = $size;
137             }
138              
139 8         1102 close($pipe);
140              
141 8         140 return \%usage;
142             }
143              
144             1;
145             __END__