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   241345 use strict;
  3         26  
  3         84  
4 3     3   15 use warnings;
  3         6  
  3         80  
5              
6 3     3   20 use Carp qw(croak);
  3         5  
  3         119  
7 3     3   942 use Symbol ();
  3         1710  
  3         3150  
8              
9             our ($VERSION, $DU_BIN);
10              
11             $VERSION = '0.23';
12              
13             $DU_BIN = '/usr/bin/du';
14              
15             sub TIEHASH
16             {
17 3     3   148 my $class = shift;
18              
19 3         9 my $du = _locate_du();
20 3         6 my $path = shift @_;
21 3         7 my @opts = @_;
22              
23 3         10 _validate($path, \@opts);
24              
25 3         22 return bless { du => $du, path => $path, opts => \@opts }, $class;
26             }
27              
28             sub EXISTS
29             {
30 1     1   13 my $self = shift;
31 1         3 my ($key) = @_;
32              
33 1         4 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, $key);
34              
35 1         87 return exists $usage->{$key};
36             }
37              
38             sub FETCH
39             {
40 3     3   138 my $self = shift;
41 3         22 my ($key) = @_;
42              
43 3         30 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, $key);
44              
45 3         168 return $usage->{$key};
46             }
47              
48             sub FIRSTKEY
49             {
50 3     3   18 my $self = shift;
51              
52 3         23 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, undef);
53              
54 3         64 my @keys = sort keys %$usage;
55 3         14 my $key = shift @keys;
56 3         22 delete $self->{'keys'};
57 3         23 $self->{'keys'} = [ @keys ];
58              
59 3         134 return $key;
60             }
61              
62             sub NEXTKEY
63             {
64 2     2   10 my $self = shift;
65              
66 2         14 return shift @{$self->{'keys'}};
  2         87  
67             }
68              
69             sub SCALAR
70             {
71 1     1   9 my $self = shift;
72              
73 1         12 my $usage = _parse_usage($self->{du}, $self->{path}, $self->{opts}, undef);
74              
75 1         67 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   2784 my ($path, $opts) = @_;
85              
86 10 100 100     22 @$opts = map { (defined && length) ? $_ : () } @$opts;
  6         34  
87              
88 10         38 my %errors = (
89             not_exists => 'an existing path',
90             not_option => 'options to be short or long',
91             );
92 10     0   49 my $error = sub { "tie() requires $_[0]" };
  0         0  
93              
94 10         46 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     174 if defined $path && !-e $path;
103              
104             croak $error->($errors{not_option})
105 10 50 66     134 if @$opts && grep !/$valid_opt/, @$opts;
106             }
107              
108             sub _locate_du
109             {
110 3 100   3   159 if (!-e $DU_BIN) {
111 1         8 my $du_which = do { require File::Which; File::Which::which('du') };
  1         723  
  1         1407  
112 1 50       244 croak "Cannot locate du: $!" unless defined $du_which;
113              
114 1         4 return $du_which;
115             }
116             else {
117 2 50       25 croak "Cannot run `$DU_BIN': Not executable" unless -x $DU_BIN;
118              
119 2         9 return $DU_BIN;
120             }
121             }
122              
123             sub _parse_usage
124             {
125 8     8   28 my ($du, $path, $opts, $key) = @_;
126 8   33     32 $path ||= do { require Cwd; Cwd::getcwd() };
  0         0  
  0         0  
127              
128 8         66 my $pipe = Symbol::gensym();
129 8 50       18753 open($pipe, "$du @$opts $path |") or exit(1);
130              
131 8         87 my %usage;
132 8         6988 while (my $line = <$pipe>) {
133 8         350 my ($size, $item) = $line =~ /^(.+?) \s+? (.+)$/x;
134             # optimisation for EXISTS/FETCH
135 8 50 66     87 next if defined $key && $key ne $item;
136 8         207 $usage{$item} = $size;
137             }
138              
139 8         276 close($pipe);
140              
141 8         438 return \%usage;
142             }
143              
144             1;
145             __END__