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