File Coverage

blib/lib/Stow/Util.pm
Criterion Covered Total %
statement 27 48 56.2
branch 4 14 28.5
condition 6 6 100.0
subroutine 6 12 50.0
pod 4 8 50.0
total 47 88 53.4


line stmt bran cond sub pod time code
1             package Stow::Util;
2              
3             =head1 NAME
4              
5             Stow::Util - general utilities
6              
7             =head1 SYNOPSIS
8              
9             use Stow::Util qw(debug set_debug_level error ...);
10              
11             =head1 DESCRIPTION
12              
13             Supporting utility routines for L.
14              
15             =cut
16              
17 3     3   78401 use strict;
  3         6  
  3         76  
18 3     3   13 use warnings;
  3         4  
  3         78  
19              
20 3     3   2402 use POSIX qw(getcwd);
  3         22622  
  3         17  
21              
22 3     3   4161 use base qw(Exporter);
  3         5  
  3         2204  
23             our @EXPORT_OK = qw(
24             error debug set_debug_level set_test_mode
25             join_paths parent canon_path restore_cwd
26             );
27              
28             our $ProgramName = 'stow';
29              
30             #############################################################################
31             #
32             # General Utilities: nothing stow specific here.
33             #
34             #############################################################################
35              
36             =head1 IMPORTABLE SUBROUTINES
37              
38             =head2 error($format, @args)
39              
40             Outputs an error message in a consistent form and then dies.
41              
42             =cut
43              
44             sub error {
45 0     0 1 0 my ($format, @args) = @_;
46 0         0 die "$ProgramName: ERROR: " . sprintf($format, @args) . "\n";
47             }
48              
49             =head2 set_debug_level($level)
50              
51             Sets verbosity level for C.
52              
53             =cut
54              
55             our $debug_level = 0;
56              
57             sub set_debug_level {
58 0     0 1 0 my ($level) = @_;
59 0         0 $debug_level = $level;
60             }
61              
62             =head2 set_test_mode($on_or_off)
63              
64             Sets testmode on or off.
65              
66             =cut
67              
68             our $test_mode = 0;
69              
70             sub set_test_mode {
71 0     0 1 0 my ($on_or_off) = @_;
72 0 0       0 if ($on_or_off) {
73 0         0 $test_mode = 1;
74             }
75             else {
76 0         0 $test_mode = 0;
77             }
78             }
79              
80             =head2 debug($level, $msg)
81              
82             Logs to STDERR based on C<$debug_level> setting. C<$level> is the
83             minimum verbosity level required to output C<$msg>. All output is to
84             STDERR to preserve backward compatibility, except for in test mode,
85             when STDOUT is used instead. In test mode, the verbosity can be
86             overridden via the C environment variable.
87              
88             Verbosity rules:
89              
90             =over 4
91              
92             =item 0: errors only
93              
94             =item >= 1: print operations: LINK/UNLINK/MKDIR/RMDIR/MV
95              
96             =item >= 2: print operation exceptions
97              
98             e.g. "_this_ already points to _that_", skipping, deferring,
99             overriding, fixing invalid links
100              
101             =item >= 3: print trace detail: trace: stow/unstow/package/contents/node
102              
103             =item >= 4: debug helper routines
104              
105             =item >= 5: debug ignore lists
106              
107             =back
108              
109             =cut
110              
111             sub debug {
112 0     0 1 0 my ($level, $msg) = @_;
113 0 0       0 if ($debug_level >= $level) {
114 0 0       0 if ($test_mode) {
115 0         0 print "# $msg\n";
116             }
117             else {
118 0         0 warn "$msg\n";
119             }
120             }
121             }
122              
123             #===== METHOD ===============================================================
124             # Name : join_paths()
125             # Purpose : concatenates given paths
126             # Parameters: path1, path2, ... => paths
127             # Returns : concatenation of given paths
128             # Throws : n/a
129             # Comments : factors out redundant path elements:
130             # : '//' => '/' and 'a/b/../c' => 'a/c'
131             #============================================================================
132             sub join_paths {
133 14     14 0 42 my @paths = @_;
134              
135             # weed out empty components and concatenate
136 14         25 my $result = join '/', grep {! /\A\z/} @paths;
  28         89  
137              
138             # factor out back references and remove redundant /'s)
139 14         26 my @result = ();
140             PART:
141 14         82 for my $part (split m{/+}, $result) {
142 88 100       184 next PART if $part eq '.';
143 86 100 100     372 if (@result && $part eq '..' && $result[-1] ne '..') {
      100        
144 10         17 pop @result;
145             }
146             else {
147 76         153 push @result, $part;
148             }
149             }
150              
151 14         89 return join '/', @result;
152             }
153              
154             #===== METHOD ===============================================================
155             # Name : parent
156             # Purpose : find the parent of the given path
157             # Parameters: @path => components of the path
158             # Returns : returns a path string
159             # Throws : n/a
160             # Comments : allows you to send multiple chunks of the path
161             # : (this feature is currently not used)
162             #============================================================================
163             sub parent {
164 5     5 0 20 my @path = @_;
165 5         15 my $path = join '/', @_;
166 5         29 my @elts = split m{/+}, $path;
167 5         7 pop @elts;
168 5         34 return join '/', @elts;
169             }
170              
171             #===== METHOD ===============================================================
172             # Name : canon_path
173             # Purpose : find absolute canonical path of given path
174             # Parameters: $path
175             # Returns : absolute canonical path
176             # Throws : n/a
177             # Comments : is this significantly different from File::Spec->rel2abs?
178             #============================================================================
179             sub canon_path {
180 0     0 0   my ($path) = @_;
181              
182 0           my $cwd = getcwd();
183 0 0         chdir($path) or error("canon_path: cannot chdir to $path from $cwd");
184 0           my $canon_path = getcwd();
185 0           restore_cwd($cwd);
186              
187 0           return $canon_path;
188             }
189              
190             sub restore_cwd {
191 0     0 0   my ($prev) = @_;
192 0 0         chdir($prev) or error("Your current directory $prev seems to have vanished");
193             }
194              
195             =head1 BUGS
196              
197             =head1 SEE ALSO
198              
199             =cut
200              
201             1;
202              
203             # Local variables:
204             # mode: perl
205             # cperl-indent-level: 4
206             # end:
207             # vim: ft=perl