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